Skip to content

[finding] pnpm lint aborts with a V8 heap OOM (exit 134) at the default old-space limit — the script pins --stack-size but not --max-old-space-size #12261

Description

@os-zhuang

Observation

pnpm lintnode --stack-size=4000 node_modules/eslint/bin/eslint.js . --no-inline-config — aborts on a developer machine with a V8 heap OOM, not with a lint result:

<--- Last few GCs --->
[92947] 20367 ms: Scavenge (during sweeping) 4050.7 (4061.6) -> 4045.3 (4062.9) MB ... allocation failure;
[92947] 22018 ms: Incremental Mark-Compact (reduce) 4078.6 (4089.6) -> 4055.4 (4059.4) MB ...
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
----- Native stack trace -----
1: 0x104576578 node::OOMErrorHandler(...)
...
ELIFECYCLE Command failed.

Exit code 134 (SIGABRT), after ~22s. Measured 2026-08-25 on macOS 15 (darwin 25.5.0), Node v26.7.0, at 20b0fdb56.

Re-running the identical sweep with a larger heap is green with zero findings:

node --stack-size=4000 --max-old-space-size=8192 node_modules/eslint/bin/eslint.js . --no-inline-config
→ exit 0, no findings

So there is no lint defect here. The sweep has simply grown to sit at the default V8 old-space limit: it died at ~4055 MB against a default ceiling of ~4096 MB, i.e. within about 1% of it.

Why it is worth recording

  1. The script pins one memory knob and not the other.lint already carries --stack-size=4000, so the memory profile of this sweep was considered once; --max-old-space-size was not set alongside it. Several other heavy commands in the repo do set it (apps/docs's build uses NODE_OPTIONS='--max-old-space-size=4096', and next.config.mjs caps experimental.cpus for the same class of reason).

  2. The failure does not read as a lint failure. A 60-line native stack trace and ELIFECYCLE is easy to mistake for a broken toolchain or a bad checkout. It is also a shape that a cmd 2>&1 | tail -n pipeline reports as green, since the crash text scrolls past and the pipe's exit code replaces the abort.

  3. .github/workflows/lint.yml runs pnpm lint with no NODE_OPTIONS, so CI depends on the runner's default heap having headroom the sweep is measurably close to exhausting. CI is green today; the margin is the point, not a current outage.

Not verified here

  • Whether the same sweep OOMs on the CI runner (it does not today — Lint & Repo Gates is green on main).
  • Whether the growth is one pathological rule/plugin or the file count. The measurement above does not separate those, and picking a fix (raise the ceiling vs. find the allocator) should probably start there.

Source

Found while running the repo-wide lint as part of the verification for #12233. Not related to that change: the OOM reproduces on 20b0fdb56 with a clean tree.

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions