Skip to content

bug(MatSlider): showTickMarks can exhaust memory during SSR #34036

Open

Description

@SkyZeroZx

Is this a regression?

  • Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

ngAfterViewInit() measures the slider only in the browser, but it builds the tick marks on the server too:

if (this._platform.isBrowser) {
  this._updateDimensions();
}
// ...
this._updateTickMarkUI();

_updateTickMarkUINonRange() allocates one entry per tick mark:

this._tickMarks = Array(numActive)
  .fill(_MatTickMark.ACTIVE)
  .concat(Array(numInactive).fill(_MatTickMark.INACTIVE));

The template only renders them @if (_cachedWidth), and the server never sets _cachedWidth. So during SSR the array is built and thrown away, and nothing bounds its size: it is (max - min) / step.

A slider whose bounds come from the URL is enough:

@Component({
  selector: 'price-range',
  imports: [MatSliderModule],
  template: `
    <mat-slider [min]="min" [max]="max" [step]="step" showTickMarks>
      <input matSliderThumb />
    </mat-slider>
  `,
})
export class PriceRange {
  private readonly params = inject(ActivatedRoute).snapshot.queryParamMap;
  readonly min = Number(this.params.get('min') ?? '0');
  readonly max = Number(this.params.get('max') ?? '100');
  readonly step = Number(this.params.get('step') ?? '1');
}

I served it with RenderMode.Server and compared /?max=1e9 with a control of the same size, /?max=1e2. Each cell is three fresh workers, and fatal means a V8 FATAL ERROR with exit code 134:

Heap ?max=1e2 ?max=1e9
256 MiB 3/3 200 3/3 fatal, 3.0 s
1 GiB 3/3 200 3/3 fatal, 5.5 s
4 GiB 3/3 200 3/3 fatal, 5.8 s
16 GiB 3/3 200 3/3 fatal, 5.6 s
default (4,288 MiB) 3/3 200 3/3 fatal, 5.6 s

A bigger heap doesn't help. Above 2^25 entries Array(n) switches to dictionary elements, and from about 2.5e8 entries the dictionary hits V8's hash table limit before the heap fills up:

FATAL ERROR: invalid table size Allocation failed - JavaScript heap out of memory

?min=-1e9 and ?step=1e-7 also reach a billion tick marks and are fatal too. The values don't need to look odd either: ?max=1000000&step=0.01, a price with cents, is 1e8 tick marks and kills a 512 MiB worker.

#26322 fixed #26317 by skipping the array when showTickMarks is off. With it on, the count is still unbounded, and #29496 is the browser side of the same problem. #33242 rewrites the method as a push loop over Math.floor((max - min) / step) + 1, so the count doesn't change. I applied it on top of 22.2.5: ?max=1e9 still kills a 256 MiB worker, ?max=3e7 now does too, and ?step=1e-309 goes from an immediate RangeError to a fatal error.

Returning early from _updateTickMarkUI() until _cachedWidth is set, which the template already requires, makes every request above return 200. The browser still builds the full array once the slider has a width.

As a note I found this while adapting MatSlider for a design system, using its code as the base. In an e-commerce app, passing the price filter's value or range through query parameters could OOM the SSR worker, so I would think this is a normal real use case.

Reproduction

See https://github.com/SkyZeroZx/angular-material-slider-ssr-oom-lab

Steps to reproduce:

  1. npm ci && npm run build
  2. npm run serve:ssr:srr-material-oom
  3. curl "http://localhost:4000/?max=1e9"

Expected Behavior

The server renders the slider without building tick marks it can't render, and the worker keeps serving other requests.

Actual Behavior

The SSR worker aborts with a V8 fatal error (exit code 134), and every request in flight on it fails with it.

Environment

  • Angular: 22.2.4, @angular/ssr 22.2.5, Node.js 24.16.0 (also 21.2.25 and 20.3.34)
  • CDK/Material: 22.2.5 (also 21.2.14 and 20.2.14). main and 22.3.0-next.4 have the same code.
  • Browser(s): n/a, server-side rendering
  • Operating System (e.g. Windows, macOS, Ubuntu): Windows 11 x64

Activity

  1. added a commit that references this issue on Oct 30, 2026
    f2c4fc3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions