From 4c8fb3631d58e22d693aba0b89243f2e9ecb0807 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Wed, 10 Dec 2025 21:48:29 +0100 Subject: [PATCH] fix(core): throw better errors for potential circular references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently circular references in user code manifest themselves with an error like `Cannot read properties of undefined (reading 'ɵcmp')`. This is a bit cryptic so these changes add an assertion mentioning circular references. Relates to #65917. (cherry picked from commit 7be4ddef1ccb9a6b330b52b9bbdd174089755503) --- goldens/public-api/core/errors.api.md | 2 ++ packages/core/src/errors.ts | 1 + packages/core/src/render3/def_getters.ts | 15 +++++++++++++++ .../bundle.golden_symbols.json | 3 ++- .../create_component/bundle.golden_symbols.json | 3 ++- .../bundling/defer/bundle.golden_symbols.json | 3 ++- .../forms_reactive/bundle.golden_symbols.json | 3 ++- .../bundle.golden_symbols.json | 3 ++- .../bundling/hydration/bundle.golden_symbols.json | 3 ++- .../bundling/router/bundle.golden_symbols.json | 3 ++- .../bundle.golden_symbols.json | 3 ++- 11 files changed, 34 insertions(+), 8 deletions(-) diff --git a/goldens/public-api/core/errors.api.md b/goldens/public-api/core/errors.api.md index d56446070b9..36a877dd41a 100644 --- a/goldens/public-api/core/errors.api.md +++ b/goldens/public-api/core/errors.api.md @@ -34,6 +34,8 @@ export const enum RuntimeErrorCode { // (undocumented) CYCLIC_DI_DEPENDENCY = -200, // (undocumented) + DEF_TYPE_UNDEFINED = 919, + // (undocumented) DEFER_IN_HMR_MODE = -751, // (undocumented) DEFER_LOADING_FAILED = -750, diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index cd31ec0a4be..b76fa22aa7a 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -134,6 +134,7 @@ export const enum RuntimeErrorCode { MISSING_DIRECTIVE_DEFINITION = 916, NO_COMPONENT_FACTORY_FOUND = 917, EXTERNAL_RESOURCE_LOADING_FAILED = 918, + DEF_TYPE_UNDEFINED = 919, // Signal integration errors REQUIRED_INPUT_NO_VALUE = -950, diff --git a/packages/core/src/render3/def_getters.ts b/packages/core/src/render3/def_getters.ts index 0aca4e5ce71..3ad7f88c2ff 100644 --- a/packages/core/src/render3/def_getters.ts +++ b/packages/core/src/render3/def_getters.ts @@ -14,6 +14,7 @@ import {NG_COMP_DEF, NG_DIR_DEF, NG_MOD_DEF, NG_PIPE_DEF} from './fields'; import type {ComponentDef, DirectiveDef, PipeDef} from './interfaces/definition'; export function getNgModuleDef(type: any): NgModuleDef | null { + assertTypeDefined(type, '@NgModule'); return type[NG_MOD_DEF] || null; } @@ -36,6 +37,7 @@ export function getNgModuleDefOrThrow(type: any): NgModuleDef | never { */ export function getComponentDef(type: any): ComponentDef | null { + assertTypeDefined(type, '@Component'); return type[NG_COMP_DEF] || null; } @@ -52,13 +54,26 @@ export function getDirectiveDefOrThrow(type: any): DirectiveDef | never { } export function getDirectiveDef(type: any): DirectiveDef | null { + assertTypeDefined(type, '@Directive'); return type[NG_DIR_DEF] || null; } export function getPipeDef(type: any): PipeDef | null { + assertTypeDefined(type, '@Pipe'); return type[NG_PIPE_DEF] || null; } +function assertTypeDefined(type: any, symbolType: string): void { + if (type == null) { + throw new RuntimeError( + RuntimeErrorCode.DEF_TYPE_UNDEFINED, + (typeof ngDevMode === 'undefined' || ngDevMode) && + `Cannot read ${symbolType} metadata. This can indicate a runtime ` + + `circular dependency in your app that needs to be resolved.`, + ); + } +} + /** * Checks whether a given Component, Directive or Pipe is marked as standalone. * This will return false if passed anything other than a Component, Directive, or Pipe class diff --git a/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json b/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json index 951f301d8a9..c07b6161447 100644 --- a/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json @@ -339,6 +339,7 @@ "areAnimationSupported", "arrRemove", "assertNotDestroyed", + "assertTypeDefined", "attachPatchData", "balancePreviousStylesIntoKeyframes", "balanceProperties", @@ -858,4 +859,4 @@ ], "lazy": [] } -} \ No newline at end of file +} diff --git a/packages/core/test/bundling/create_component/bundle.golden_symbols.json b/packages/core/test/bundling/create_component/bundle.golden_symbols.json index 5d492376276..41b83fe3bbe 100644 --- a/packages/core/test/bundling/create_component/bundle.golden_symbols.json +++ b/packages/core/test/bundling/create_component/bundle.golden_symbols.json @@ -265,6 +265,7 @@ "areAnimationSupported", "arrRemove", "assertNotDestroyed", + "assertTypeDefined", "attachPatchData", "baseElement", "bind", @@ -689,4 +690,4 @@ ], "lazy": [] } -} \ No newline at end of file +} diff --git a/packages/core/test/bundling/defer/bundle.golden_symbols.json b/packages/core/test/bundling/defer/bundle.golden_symbols.json index 900b22feb46..6f03d12c791 100644 --- a/packages/core/test/bundling/defer/bundle.golden_symbols.json +++ b/packages/core/test/bundling/defer/bundle.golden_symbols.json @@ -310,6 +310,7 @@ "areAnimationSupported", "arrRemove", "assertNotDestroyed", + "assertTypeDefined", "attachPatchData", "bind", "bindingUpdated", @@ -744,4 +745,4 @@ "writeToDirectiveInput" ] } -} \ No newline at end of file +} diff --git a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json index 9313004bfd3..ae1a72f0cdd 100644 --- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json @@ -371,6 +371,7 @@ "assertControlPresent", "assertNotDestroyed", "assertPlatform", + "assertTypeDefined", "attachPatchData", "baseElement", "bind", @@ -1018,4 +1019,4 @@ ], "lazy": [] } -} \ No newline at end of file +} diff --git a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json index c7814601060..25eba8d8b90 100644 --- a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json @@ -375,6 +375,7 @@ "assertControlPresent", "assertNotDestroyed", "assertPlatform", + "assertTypeDefined", "attachPatchData", "baseElement", "bind", @@ -1018,4 +1019,4 @@ ], "lazy": [] } -} \ No newline at end of file +} diff --git a/packages/core/test/bundling/hydration/bundle.golden_symbols.json b/packages/core/test/bundling/hydration/bundle.golden_symbols.json index df18ccd711c..c57cab4dee5 100644 --- a/packages/core/test/bundling/hydration/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hydration/bundle.golden_symbols.json @@ -305,6 +305,7 @@ "areAnimationSupported", "arrRemove", "assertNotDestroyed", + "assertTypeDefined", "attachPatchData", "baseElement", "bind", @@ -797,4 +798,4 @@ ], "lazy": [] } -} \ No newline at end of file +} diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index 5bf3acf7ebd..4b954c2eb34 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -415,6 +415,7 @@ "arrRemove", "arrayEquals", "assertNotDestroyed", + "assertTypeDefined", "attachPatchData", "baseElement", "bind", @@ -1148,4 +1149,4 @@ ], "lazy": [] } -} \ No newline at end of file +} diff --git a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json index e9f7ff4db87..9a3ce443f93 100644 --- a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json +++ b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json @@ -245,6 +245,7 @@ "areAnimationSupported", "arrRemove", "assertNotDestroyed", + "assertTypeDefined", "attachPatchData", "baseElement", "bind", @@ -629,4 +630,4 @@ ], "lazy": [] } -} \ No newline at end of file +}