Skip to content

Troubleshooting

Read the stable code first:

  • CONFIG_NOT_FOUND--config did not name a file.
  • CONFIG_LOAD_FAILED — module evaluation or import resolution failed.
  • CONFIG_EXPORT_INVALID — the module did not default-export an object.

For load failures:

  1. Confirm tsconfigPath points at the consumer’s real alias-owning config.
  2. Import a Node-safe contracts entry point instead of an Angular barrel.
  3. Keep every alias imported by that entry point in the tool config; TypeScript paths objects do not merge entry by entry through extends.
  4. Run pnpm exec formly-contracts list before generate.

Use the Angular-aware binary when selected project configs legitimately load partially compiled Angular code:

Terminal window
pnpm exec formly-contracts-angular list \
--project-config libs/forms-kit/formly-contracts.project.ts \
--explain

Default output retains the stable worker code and phase while hiding the underlying exception. --explain requests a bounded local cause chain and only stack frames inside the workspace. It never enables raw child stderr or writes the explanation into generated artifacts. Review before sharing: an application-thrown message may still contain private identifiers.

A browser barrel fails before a component is initialized

Section titled “A browser barrel fails before a component is initialized”

An error such as Cannot access 'NumberComponent' before initialization is a JavaScript module initialization failure. It is different from Angular’s missing-JIT-compiler error and can remain after switching to formly-contracts-angular.

If an Angular component refers to itself in decorator provider metadata, use Angular’s documented deferred reference:

import { forwardRef } from '@angular/core';
{
provide: FORM_FIELD_CONTROL,
useExisting: forwardRef(() => NumberComponent),
}

Apply that change only when the failing edge is the component self-reference; forwardRef is not a generic repair for every circular import. Then keep the contract worker out of the broader browser graph by importing a dedicated @work/forms-kit/contracts entry point. The Node-safe Angular libraries guide shows the full boundary and a temporary leaf-import shim.

Project patterns are relative to the workspace root. Use excludeProjectConfigs for legacy or generated trees. Discovery prunes dependencies, Git metadata, and the effective output directory, but it does not exclude every directory named dist.

Project-config symlinks are rejected. Keep real configs inside the workspace.

Discovery failures carry one of these stable codes:

  • CONFIG_PATH_OUTSIDE_WORKSPACE — a matched project config resolves outside the workspace root.
  • DUPLICATE_PROJECT_ID — two discovered project configs declare the same projectId.
  • DUPLICATE_SOURCE_ID — two sources within a project declare the same sourceId.
  • PROJECT_CONFIG_SYMLINK_UNSUPPORTED — a matched project config path is a symlink.

runWorkspace/checkWorkspace throw a WorkspaceGenerationError with one of these codes:

  • WORKSPACE_DISCOVERY_FAILED — workspace discovery failed.
  • PROJECT_CONFIG_RESOLUTION_FAILED — a project’s configuration failed to resolve.
  • SOURCE_LIST_FAILED — a form contract source could not be listed.
  • SOURCE_LIST_INVALID — a form contract source returned an invalid list.
  • FORM_DEFINITION_INVALID — a form contract definition is invalid.
  • DUPLICATE_FORM_ID — a form ID is declared more than once.
  • FORM_FACTORY_FAILED — a form contract factory failed.
  • FORM_INSTANCE_INVALID — a form contract factory returned an invalid instance.
  • CONTRACT_EXTRACTION_FAILED — form contract extraction failed.
  • SOURCE_USAGE_PROJECT_CONFIG_UNSUPPORTED — source indexing found a project config outside the pilot’s supported .ts, .mts, or .cts entry points.
  • SOURCE_USAGE_INDEX_FAILED — the configured TypeScript source-usage program could not be built or indexed within the workspace boundary.
  • DIAGNOSTIC_POLICY_FAILED — a generated contract violates diagnostic policy (diagnostics.failOn).
  • DEPENDENCY_SNAPSHOT_UNAVAILABLE — a pnpm dependency snapshot could not be selected.
  • RUNTIME_PROVENANCE_UNAVAILABLE — runtime toolchain provenance could not be determined.
  • OUTPUT_PATH_OUTSIDE_WORKSPACE — an output path is outside the workspace.
  • OUTPUT_SYMLINK_UNSUPPORTED — symlinked output paths are not supported.
  • OUTPUT_WRITE_FAILED — workspace contract output could not be written.

Source-usage diagnostics do not use the Form Contract diagnostics.failOn policy. Important source diagnostics include:

  • SOURCE_DESCRIPTOR_UNSUPPORTED — a discovered project config or its source registration is outside the direct canonical helper grammar, has IDs that do not match runtime inventory, or contains unsupported wrapped/spread/dynamic source elements. No same-ID fallback is attempted.
  • SOURCE_DESCRIPTOR_CONFLICT — more than one canonical registration claims the same project/source authority. Remove the duplicate; neither claim is selected by source order.
  • SOURCE_FILE_SNAPSHOT_MISMATCH — final file bytes do not match the TypeScript SourceFile.text that established authority or a usage. Every exact usage depending on that file is suppressed, not just usages physically located in it.
  • SOURCE_RUNTIME_RESOLUTION_MISMATCH — TypeScript and the exact Jiti runtime used for config evaluation selected different canonical files for a traversed authority import or re-export. Align the root resolver settings or use an import shape supported consistently by both.
  • SOURCE_USAGE_UNSUPPORTED — a recognized callsite is unsafe for exact linkage, including unchecked JavaScript-family files and TypeScript files containing @ts-nocheck, @ts-ignore, or @ts-expect-error directives.

Run generate and check against a quiescent checkout and stop watchers that rewrite authority files during the pass. The authority and application TypeScript Programs are created before form factories execute, but the MVP does not snapshot every runtime/Jiti-loaded module and retains a short config-loading-to-Program boundary. Source coverage is intentionally incomplete, so an unsupported out-of-grammar call is not guaranteed to produce a per-call diagnostic.

UNMAPPED_FIELD_TYPE means extraction preserved the field but had no reviewed operational profile. Formly’s { name, component } registration cannot supply that meaning by itself.

When a shipped preset matches the component, define one contracted type, derive its Formly registration, and lower the same definition into the project registry:

export const MONEY_INPUT_TYPE = defineContractedFormlyType({
name: 'money-input',
profile: { id: 'claims.money-input', version: 1 },
behavior: typedInput({ semanticType: 'currency', role: 'spinbutton' }),
});
toFormlyTypeRegistration(MONEY_INPUT_TYPE, MoneyInputComponent);
export const FIELD_PROFILES = buildFieldTypeProfileRegistry({
id: 'claims.fields',
version: 1,
types: [MONEY_INPUT_TYPE],
});

Attach FIELD_PROFILES as the owning project’s fieldTypeProfiles. If a profile already exists, confirm its generated registration matches the exact field type and selected variant. Declare wrapper behavior with defineContractedFormlyWrapper(...), include it in the builder’s wrappers, and reuse its exact name in Formly’s ordinary wrapper registration.

If no preset matches losslessly, keep an explicit reviewed legacy profile or the diagnostic. Do not map a type to the nearest native widget by appearance. See Custom field profiles for the complete paired flow and shipped preset list.

Function- or async-backed options remain dynamic during declared extraction. Add a named synthetic scenario in a trusted Angular/Formly environment for each meaningful branch. The result is complete for that scenario only.

Run generate, inspect the contract diff and diagnostics, and commit or publish the new artifact set according to the consumer’s policy. Do not overwrite one hashed contract while leaving an old workspace index in place.

Common intentional causes include field configuration changes, locator-policy changes, profile registry changes, tool/runtime provenance changes, and lockfile changes.

Stop. Check the node’s locators and diagnostics. A missing locator is missing evidence. Add an application-owned test attribute or improve a reviewed profile and regenerate; do not fall back to an invented CSS selector.