From bb65520991eede8f63454db4fd237eeee689eb41 Mon Sep 17 00:00:00 2001 From: SkyZeroZx <73321943+SkyZeroZx@users.noreply.github.com> Date: Sun, 14 Dec 2025 12:10:48 -0500 Subject: [PATCH] docs: Adds documentation for the NG0919 error Adds a new documentation page for the NG0919 error, which indicates a circular dependency in Angular applications. fixes #65968 --- adev/src/content/reference/errors/NG0919.md | 99 +++++++++++++++++++ adev/src/content/reference/errors/overview.md | 1 + goldens/public-api/core/errors.api.md | 2 +- packages/core/src/errors.ts | 2 +- 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 adev/src/content/reference/errors/NG0919.md diff --git a/adev/src/content/reference/errors/NG0919.md b/adev/src/content/reference/errors/NG0919.md new file mode 100644 index 00000000000..ae1c76efece --- /dev/null +++ b/adev/src/content/reference/errors/NG0919.md @@ -0,0 +1,99 @@ +# Circular Dependency Detected + +Angular detected a circular dependency between components, directives, or pipes. This error occurs when component A imports component B, and component B (directly or indirectly) imports component A, creating a cycle. + +This circular reference prevents Angular from properly initializing the components, resulting in an error like: + +```text +NG0919: Cannot read @Component metadata. This can indicate a runtime circular dependency in your app that needs to be resolved. +``` + +In older Angular versions, you might instead see an error like: + +```text +Cannot read properties of undefined (reading 'ɵcmp') +``` + +## Common Causes + +### Mutual Component Imports + +The most common cause is when two components import each other: + +```angular-ts {header:"parent.component.ts"} +import {Component} from '@angular/core'; +import {ChildComponent} from './child.component'; + +@Component({ + selector: 'app-parent', + imports: [ChildComponent], + template: '', +}) +export class ParentComponent {} +``` + +```angular-ts {header:"child.component.ts"} +import {Component} from '@angular/core'; +import {ParentComponent} from './parent.component'; + +@Component({ + selector: 'app-child', + imports: [ParentComponent], + template: '', +}) +export class ChildComponent {} +``` + +### Indirect Circular References + +Circular dependencies can also occur through intermediate files: + +```text +ComponentA -> ComponentB -> ComponentC -> ComponentA +``` + +## Resolving the error + +### Refactor shared logic + +Move shared functionality to a separate file that doesn't import either component: + +```angular-ts {header:"shared.service.ts"} +import {Injectable} from '@angular/core'; + +@Injectable({providedIn: 'root'}) +export class SharedService { + // Shared logic here +} +``` + +### Use type-only imports + +If you only need types for TypeScript, use `import type`: + +```ts +import type {ParentComponent} from './parent.component'; +``` + +Type-only imports are erased at compile time and don't contribute to runtime circular dependencies. + +### Restructure component hierarchy + +Consider whether the circular dependency indicates a design issue. Often, extracting shared functionality into a third component or service is the cleanest solution. + +### Debugging complex circular dependencies + +For complex applications with many modules, circular dependencies can be difficult to identify manually. Consider using tools like [madge](https://www.npmjs.com/package/madge) to visualize and detect circular imports: + +```bash +# Install madge +npm install -g madge + +# Check for circular dependencies +madge --circular --extensions ts ./src + +# Generate a visual graph +madge --circular --extensions ts --image graph.svg ./src +``` + +These tools can help identify circular dependency chains across your entire project and generate visual dependency graphs. diff --git a/adev/src/content/reference/errors/overview.md b/adev/src/content/reference/errors/overview.md index 00fb3dbf237..00a821988e6 100644 --- a/adev/src/content/reference/errors/overview.md +++ b/adev/src/content/reference/errors/overview.md @@ -25,6 +25,7 @@ | `NG0750` | [@defer dependencies failed to load](errors/NG0750) | | `NG0910` | [Unsafe bindings on an iframe element](errors/NG0910) | | `NG0912` | [Component ID generation collision](errors/NG0912) | +| `NG0919` | [Circular Dependency Detected](errors/NG0919) | | `NG0955` | [Track expression resulted in duplicated keys for a given collection](errors/NG0955) | | `NG0956` | [Tracking expression caused re-creation of the DOM structure](errors/NG0956) | | `NG01101` | [Wrong Async Validator Return Type](errors/NG01101) | diff --git a/goldens/public-api/core/errors.api.md b/goldens/public-api/core/errors.api.md index 36a877dd41a..56bb883d919 100644 --- a/goldens/public-api/core/errors.api.md +++ b/goldens/public-api/core/errors.api.md @@ -34,7 +34,7 @@ export const enum RuntimeErrorCode { // (undocumented) CYCLIC_DI_DEPENDENCY = -200, // (undocumented) - DEF_TYPE_UNDEFINED = 919, + DEF_TYPE_UNDEFINED = -919, // (undocumented) DEFER_IN_HMR_MODE = -751, // (undocumented) diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index b76fa22aa7a..3cba1178a71 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -134,7 +134,7 @@ export const enum RuntimeErrorCode { MISSING_DIRECTIVE_DEFINITION = 916, NO_COMPONENT_FACTORY_FOUND = 917, EXTERNAL_RESOURCE_LOADING_FAILED = 918, - DEF_TYPE_UNDEFINED = 919, + DEF_TYPE_UNDEFINED = -919, // Signal integration errors REQUIRED_INPUT_NO_VALUE = -950,