You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Certain @let values can mimic internal data structure, breaking basic runtime logic #59504
Which @angular/* package(s) are the source of the bug?
core
Is this a regression?
Yes
Description
Before hydration and using signals my code worked. I refactored it to use signals and incremental hydration and it broke. The error message was not really meaningful: Cannot add property i18nNodes, object is not extensible
I use apollo-angular which freezes every object in its state and results. The state cannot be modified.
Please provide a link to a minimal reproduction of the bug
No response
Please provide the exception or error you saw
Cannot add property i18nNodes, object is not extensible
The line where the error has happened is https://github.com/angular/angular/blob/4491704fbaec02db8eec5845ffbb200dbf2a0bf6/packages/core/src/hydration/i18n.ts#L660
Please provide the environment you discovered this bug in (run ng version)
NX 20.3.0
Angular 19.0.5
Angular SSR 19.0.6
Anything else?
Workaround:
Unfreeze the object using some hacky js code: const unfrozenObj = JSON.parse(JSON.stringify(obj));
Possible solutions:
Check before trying to set the values if the object is frozen using: Object.isExtensible(object).
Throw an error that the state is not extensible and provide some information on the current component which has the error.
Show a warning during development and provide some information on the current component which has the error. In production mode ignore it.
Ignore setting the values without any warning.
I am very happy to code and make a PR on any of the solutions if the Angular team has decided.
I was not able to reproduce it, but in my lView list I can see my array that is frozen. I don't know how to put data there, I've been trying for more than an hour now. I have tried @let@if@for.
In my original code I use a state key to store the data. That is not frozen. Then the library updates it with the frozen data. Then the hydration runs.
@Component({
selector: 'app-root',
template: `
@let list = [0, {}, 0, 0, 0, 0, 1];
<!-- index 6 is important for repro-->
@if (true) { {{ list }}}
`,
})
export class AppComponent {}
For the Let Declaration to be mistaken for a LView, index:1 must be an object.
changed the title [-]Cannot add property i18nNodes, object is not extensible[/-][+]Certain `@let` values can mimic internal data structure, breaking basic runtime logic[/+]on Jan 16, 2025
@alxhub also brought up an idea to use T data structures (TNodes) to identify the type of value stored in a given LView slot. This would require some refactoring around existing places where isLView and isLContainer are used to bring T data structure where needed.
If you agree on the solution I am happy to create the PR. I have found a bug and I would love to fix Angular. 😍
@csutorasr thanks for your interest in contributing to Angular. We still need to figure out the best path forward and some of the options (using T data structures) might require complex refactoring. We'll discuss possible solutions with the team and will keep this thread updated.
In lieu of opening a new issue this is likely a related case when having a @let inside a content projection slot produces the error Error: NG0502: During serialization, Angular was unable to find an element in the DOM:
@griest024 Is this all the code that you have? Or are there any other code in the projected html? If there's none, then no components can use the var because there's nothing in the scope of that element.
I don't think it is related and I close this issue as it was resolved by the PR.
Activity
JeanMeche commentedon Jan 13, 2025
Hi, could you please provide a stackblitz reproduction or a minimal project on a github repo. Thank you.
csutorasr commentedon Jan 13, 2025
I was not able to reproduce it, but in my lView list I can see my array that is frozen. I don't know how to put data there, I've been trying for more than an hour now. I have tried
@let@if@for.In my original code I use a state key to store the data. That is not frozen. Then the library updates it with the frozen data. Then the hydration runs.
EDIT: Here is the code that I made for reproduce the error which was not successfully reproduced: https://stackblitz.com/edit/stackblitz-starters-v39odskh?file=src%2Fapp%2Fapp.component.ts
My HTML in the original code looks like this:
If I move the
@lets next to the usage, the error goes away. So being deeply nested puts the array into the lView array.csutorasr commentedon Jan 14, 2025
Probably this optimization hides my let declaration in the stackblitz example.csutorasr commentedon Jan 14, 2025
I have found the bug. If the data in the
@letis an array,or an object with athen it finds it as a hydration data in this line:6key,angular/packages/core/src/hydration/i18n.ts
Line 650 in 4491704
csutorasr commentedon Jan 14, 2025
The cleanup is referenced here:
angular/packages/core/src/hydration/cleanup.ts
Line 99 in 412ac30
So this check has the error:
angular/packages/core/src/hydration/cleanup.ts
Line 106 in 412ac30
The isLView function has the error:
angular/packages/core/src/render3/interfaces/type_checks.ts
Line 19 in 412ac30
Every array that is stored in a
LetDeclarationis considered as an LView.If the array has a 6th element, then the error happens.
Possible solution:
Mark LViews or LetDeclarations to be able to distinguish the two arrays.
JeanMeche commentedon Jan 14, 2025
A minimal repro :
For the Let Declaration to be mistaken for a LView, index:1 must be an object.
9 remaining items
[-]Cannot add property i18nNodes, object is not extensible[/-][+]Certain `@let` values can mimic internal data structure, breaking basic runtime logic[/+]AndrewKushnir commentedon Jan 16, 2025
@alxhub also brought up an idea to use
Tdata structures (TNodes) to identify the type of value stored in a givenLViewslot. This would require some refactoring around existing places whereisLViewandisLContainerare used to bringTdata structure where needed.csutorasr commentedon Jan 16, 2025
@AndrewKushnir I agree on the first option, as it fits into the current code and has the less impact.
Adding a new condition to every
isLViewcheck would impact the performance a lot. These checks happen during initial rendering.If you agree on the solution I am happy to create the PR. I have found a bug and I would love to fix Angular. 😍
AndrewKushnir commentedon Jan 17, 2025
@csutorasr thanks for your interest in contributing to Angular. We still need to figure out the best path forward and some of the options (using
Tdata structures) might require complex refactoring. We'll discuss possible solutions with the team and will keep this thread updated.fix(core): avoid confusion between let value and internal data struct…
griest024 commentedon Oct 3, 2025
In lieu of opening a new issue this is likely a related case when having a
@letinside a content projection slot produces the errorError: NG0502: During serialization, Angular was unable to find an element in the DOM:Moving the let outside the slot fixes the issue.
csutorasr commentedon Oct 27, 2025
@griest024 Is this all the code that you have? Or are there any other code in the projected html? If there's none, then no components can use the var because there's nothing in the scope of that element.
I don't think it is related and I close this issue as it was resolved by the PR.
csutorasr commentedon Oct 27, 2025
Oh, sorry it was not resolved by the PR that is mentioned, but further changes to the code had resolved it.
angular-automatic-lock-bot commentedon Nov 27, 2025
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.