Skip to content

After upgrade from angular 7 to 15 page rendering fails with error #53245

Open

Description

@kochetkovSergeY

Which @angular/* package(s) are the source of the bug?

core

Is this a regression?

Yes

Description

After upgrade from angular 7 to 15 page rendering fails with error

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/stackblitz-starters-xejxq3

Please provide the exception or error you saw

`RangeError: Invalid string length
    at Array.join (<anonymous>)
    at Array.toString (<anonymous>)
    at getOrCreateNodeInjectorForNode (vendor.js:239616:63)
    at initializeDirectives (vendor.js:247200:24)
    at resolveDirectives (vendor.js:247187:7)
    at elementStartFirstCreatePass (vendor.js:249740:3)
    at ɵɵelementStart (vendor.js:249774:41)
    at Module.ɵɵelement (vendor.js:249849:3)
    at PageaccruallistComponent_Template (src_ts_generated-sources_page-accrual-list_module_ts.js:91587:63)
    at executeTemplate (vendor.js:246773:5)`

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 15.2.10
Node: 14.21.1
Package Manager: npm 6.14.17
OS: win32 x64

Angular: 15.2.10
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, platform-server
... router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1502.10
@angular-devkit/build-angular   15.2.10
@angular-devkit/core            15.2.10
@angular-devkit/schematics      15.2.10
@angular/cdk                    15.2.9
@schematics/angular             15.2.10
rxjs                            7.8.1
typescript                      4.9.5

Anything else?

No response

Activity

  1. JoostK commented on Nov 29, 2023

    @JoostK
    Member

    This would require a reproduction to be actionable. I think your best path forward would be to have a breakpoint for when the exception occurs, to them inspect the values that result in this error.

  2. added
    needs reproductionThis issue needs a reproduction in order for the team to investigate further
    on Nov 29, 2023
  3. kochetkovSergeY commented on Nov 29, 2023

    @kochetkovSergeY
    Author

    Here is example:

    https://stackblitz.com/edit/stackblitz-starters-xejxq3

    But it's not working on stackblitz, you can download it, install dependencies and run npm run start.

    Then on the start page there is a link "link to accrual-list" to child huge page

    you have to wait few minutes after clicking the link, browser stuck for some time - then the error occures in console

  4. JoostK commented on Nov 29, 2023

    @JoostK
    Member

    Okay, this appears to fail because the number of child elements exceeds the bitsize that is available for children in an internal data structure.

    In development mode, the following root cause error is reported:

    ASSERTION ERROR: Parent injector must be pointing past HEADER_OFFSET. [Expected=> 22 > 4 <=Actual]

  5. spock123 commented on Nov 29, 2023

    @spock123

    @kochetkovSergeY if I were you I would migrate from v7 -> v8 first,.. and so on

  6. added this to the Backlog milestone on Nov 29, 2023
  7. added and removed
    needs reproductionThis issue needs a reproduction in order for the team to investigate further
    on Nov 29, 2023
  8. modified the milestones: Backlog, needsTriage on Nov 29, 2023
  9. kochetkovSergeY commented on Nov 30, 2023

    @kochetkovSergeY
    Author

    Okay, this appears to fail because the number of child elements exceeds the bitsize that is available for children in an internal data structure.

    In development mode, the following root cause error is reported:

    ASSERTION ERROR: Parent injector must be pointing past HEADER_OFFSET. [Expected=> 22 > 4 <=Actual]

    This message does not seem clear to everyone. I think this must be changed to more understandable variant

  10. kochetkovSergeY commented on Nov 30, 2023

    @kochetkovSergeY
    Author

    @kochetkovSergeY if I were you I would migrate from v7 -> v8 first,.. and so on

    We are following the migration guide and we've almost finished the migration

    I don't see any point in switching to 8 and so on...

  11. added
    needs reproductionThis issue needs a reproduction in order for the team to investigate further
    on Dec 6, 2023
  12. 23 remaining items

  13. lanminik commented on Mar 6, 2024

    @lanminik

    How I 'solved' the issue... My SVG had a lot of directives and a lot of html attributes attached to it as I mentioned in my comment above. Moved all of them ether away or to the parent element helped a lot. I had markForCheck() called number of times (in the component that handles the SVG) and reducing that helped as well. I am not sure that I've solved the issue completely but at least these adjustments changed threshold until error happens again. I hope that this can help you guys as well...

  14. venkatesh-gardas commented on Mar 20, 2024

    @venkatesh-gardas

    @alxhub
    @atscott
    @JoostK
    Please provide any workaround or update on this issue.

  15. kochetkovSergeY commented on Apr 11, 2024

    @kochetkovSergeY
    Author

    Okay, this appears to fail because the number of child elements exceeds the bitsize that is available for children in an internal data structure.

    In development mode, the following root cause error is reported:

    ASSERTION ERROR: Parent injector must be pointing past HEADER_OFFSET. [Expected=> 22 > 4 <=Actual]

    @JoostK Could you give instructions or workaround how to increase internal data structure size? We've decreased by 5 times number of child elements, but error still appears,

    It doesn't look like the problem will be resolved any time soon...

  16. atscott commented on Apr 11, 2024

    @atscott
    Contributor

    I've made a much smaller reproduction here: https://stackblitz.com/edit/stackblitz-starters-ew6f7z (again, it has to be downloaded and run locally)

  17. kochetkovSergeY commented on May 24, 2024

    @kochetkovSergeY
    Author

    Angular 18 - the problem is still occurs…

    Example - https://stackblitz.com/edit/stackblitz-starters-cj1r3m

    Error stack:

    chunk-6HSZQENR.js?v=856b5065:8014 ERROR RangeError: Maximum call stack size exceeded
        at executeTemplate (chunk-6HSZQENR.js?v=856b5065:10601:5)
        at renderView (chunk-6HSZQENR.js?v=856b5065:11387:7)
        at renderComponent (chunk-6HSZQENR.js?v=856b5065:11369:3)
        at renderChildComponents (chunk-6HSZQENR.js?v=856b5065:11416:5)
        at renderView (chunk-6HSZQENR.js?v=856b5065:11401:7)
        at renderComponent (chunk-6HSZQENR.js?v=856b5065:11369:3)
        at renderChildComponents (chunk-6HSZQENR.js?v=856b5065:11416:5)
        at renderView (chunk-6HSZQENR.js?v=856b5065:11401:7)
        at ComponentFactory.create (chunk-6HSZQENR.js?v=856b5065:14044:9)
        at _ApplicationRef.bootstrap (chunk-6HSZQENR.js?v=856b5065:22471:38)
    
  18. kochetkovSergeY commented on Aug 21, 2024

    @kochetkovSergeY
    Author

    any update?

  19. apappas1129 commented on Jun 13, 2025

    @apappas1129

    @kochetkovSergeY We are following the migration guide and we've almost finished the migration

    I don't see any point in switching to 8 and so on...

    Hi @kochetkovSergeY, I recently upgraded two very large Angular projects that had a significant version leap and I encountered similar error messages during the process. I’ll try to track down exactly when I ran into this issue and see if I can help.

    That said, I strongly agree with the recommendation not to skip major versions. It's important to upgrade incrementally—go from v8 to v9 first, then v9 to v10, and so on. This allows ng update to handle necessary migration steps properly, especially if you're using packages like Angular Material.

    This recommendation is explicitly stated in the Angular documentation:

    You can ng update to any version of Angular, provided that the following criteria are met:

    • The version you want to update to is supported.
    • The version you want to update from is within one major version of the version you want to upgrade to.

    For example, you can update from version 11 to version 12, provided that version 12 is still supported. If you want to update across multiple major versions, perform each update one major version at a time. For example, to update from version 10 to version 12:

    1. Update from version 10 to version 11.
    2. Update from version 11 to version 12.

    More than that, if you have 3rd party dependencies, you will also have to resolve them before you hop to the next version. For example, I had @microsoft/applicationinsights-angularplugin-js 2.6.2, which wasn't compatible with v13. I had to refer to their Compatibility Matrix to find out that I needed to upgrade to 2.9.2. In many cases, though, other libraries don’t provide a clear compatibility guide—so you may need to dig through commit histories or cross-reference release dates between Angular and the library to find a working version. Another example, if you are using @angular/flex-layout, you will find out that the team stopped publishing new releases starting in v15 so you will have to manually migrate to a modern CSS tooling like Tailwind or at least convert your flex-layout directives to their raw CSS equivalent. Even libraries like RxJS may introduce stealth patches that don’t break your build but can lead to runtime issues. So you also have to consider regression tests on your features after each upgrade to catch any unexpected behavior early.

  20. kochetkovSergeY commented on Oct 6, 2026

    @kochetkovSergeY
    Author

    Root cause found. Still reproducible on v22.2.1 (current latest) and v18.2.14. Proposed fix is two constants.

    Root cause

    The location of a node's parent injector is packed into one number (RelativeInjectorLocation): the low 15 bits hold the index of the parent injector in the LView, bits 16+ hold the declaration-view offset.

    • packages/core/src/render3/interfaces/injector.ts: InjectorIndexMask = 0b111111111111111 (max 32767), ViewOffsetShift = 16
    • packages/core/src/render3/di.ts, getParentInjectorLocation(): returns tNode.parent.injectorIndex or parentTNode.injectorIndex | (declarationViewOffset << ViewOffsetShift) without a range check
    • packages/core/src/render3/util/injector_utils.ts, getParentInjectorIndex(): parentLocation & InjectorIndexMask

    tNode.injectorIndex is lView.length at the moment the injector is created (getOrCreateNodeInjectorForNode), i.e. an absolute index into the LView. The LView grows with the template: HEADER_OFFSET + 1 slot per node + 1 per binding + 1 per directive instance + 9 per element that has at least one directive (8 bloom words + parent location). An element with a single directive/component therefore costs ~11 slots, and once a template holds roughly 2,900 of them, every injector created after that lands at an index >= 32768. Each descendant (or child-component node) that points at it gets a truncated parent index.

    Depending on where the truncated index lands:

    • dev mode: ASSERTION ERROR: Parent injector must be pointing past HEADER_OFFSET (this issue)
    • prod mode: the index hits a header slot holding an array/LView, and parentLView[parentIndex + i] | parentData[parentIndex + i] calls Array.prototype.toString -> RangeError: Invalid string length (this issue) or Maximum call stack size exceeded
    • any other slot: the cumulative bloom filter is silently filled with garbage; the first visible effect is a bogus NG0201: No provider found for X for a token provided by an ancestor element
    • index >= 65536: the view-offset bits are corrupted as well and getParentInjectorView walks past the root (TypeError: Cannot read properties of null (reading '1'))

    The limit is per LView. Embedded views (*ngIf, @if, @for, ng-template) and child components get their own index space, which is why most apps never hit it, and why "reduce the number of children" did not help here (bindings and directive instances count too).

    Minimal reproduction (Node, same runtime code path as the browser)

    // npm i @angular/{core,compiler,common,platform-browser,platform-server}@22 rxjs zone.js
    // node repro.mjs 2851        -> OK
    // node repro.mjs 3000        -> ASSERTION ERROR: Parent injector must be pointing past HEADER_OFFSET
    // node repro.mjs 3000 prod   -> RangeError: Invalid string length
    import '@angular/compiler';
    import 'zone.js';
    import { Component, Directive, provideZonelessChangeDetection } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import { renderApplication } from '@angular/platform-server';
    
    const N = Number(process.argv[2] ?? 3000);
    if (process.argv[3] === 'prod') globalThis.ngDevMode = false;
    
    class D {}
    Directive({ selector: '[d]', standalone: true })(D);
    
    class TextField {}
    Component({ selector: 'text-field', standalone: true, imports: [D], template: '<div><span d></span></div>' })(TextField);
    
    class App {}
    Component({ selector: 'app-root', standalone: true, imports: [TextField], template: '<text-field></text-field>'.repeat(N) })(App);
    
    await renderApplication((ctx) => bootstrapApplication(App, { providers: [provideZonelessChangeDetection()] }, ctx),
      { document: '<html><body><app-root></app-root></body></html>' });
    console.log('OK');

    Threshold check: 28 (HEADER_OFFSET) + 2851 + 2851 * 10 = 31389 passes; 28 + 3000 + 3000 * 10 = 33028 fails. The number in the assertion matches the arithmetic exactly: host #2974 gets injector index 28 + 3000 + 2974 * 10 = 32768, masked to 0, hence [Expected=> 28 > 0 <=Actual] on v22 ([Expected=> 25 > 7] on v18, where HEADER_OFFSET is 25).

    Proposed fix

    Widen the index part of RelativeInjectorLocation:

    export const enum RelativeInjectorLocationFlags {
      InjectorIndexMask = 0b11111111111111111111, // 20 bits (was 15)
      ViewOffsetShift = 20,                        // was 16
      NO_PARENT = -1,
    }

    Those two constants are the only thing the runtime reads (getParentInjectorIndex, getParentInjectorViewOffset, getParentInjectorLocation). The value stays inside V8's 31-bit SMI range (20 bits index + 10 bits view offset), which allows ~1M LView slots per template and still 1023 nested declaration views. I applied exactly this change to the 22.2.1 bundle: all failing cases above pass (3,000 and 12,000 hosts, dev and prod, the NG0201 case, the >= 65536 case), and the cases with non-zero view offsets (@for, *ngIf/@if blocks, nested components) still pass.

    Independently of that, getParentInjectorLocation() should assert injectorIndex <= InjectorIndexMask in dev mode with a message that says the template is too large and how to split it, instead of the current assertion / RangeError that gives no hint.

  21. JeanMeche commented on Oct 6, 2026

    @JeanMeche
    Member

    Hello, we reviewed this issue and determined that it doesn't fall into the bug report or feature request category. This issue tracker is not suitable for support requests, please repost your issue on StackOverflow using tag angular.

    If you are wondering why we don't resolve support issues via the issue tracker, please check out this explanation.

  22. JoostK commented on Oct 6, 2026

    @JoostK
    Member

    getParentInjectorLocation() should assert injectorIndex <= InjectorIndexMask in dev mode with a message that says the template is too large and how to split it, instead of the current assertion / RangeError that gives no hint.

    This is worth doing IMO

  23. reopened this on Oct 6, 2026
  24. atscott commented on Oct 6, 2026

    @atscott
    Contributor

    Would you mind sending a PR over for this? The fix seems reasonable and correct.

  25. kochetkovSergeY commented on Oct 6, 2026

    @kochetkovSergeY
    Author

    Would you mind sending a PR over for this? The fix seems reasonable and correct.

    Yes, I send a PR tomorrow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions