Skip to content

compiler memory leak in 5.8.x and upwards #62143

Open

Description

@fxdave

🔎 Search Terms

5.8, mem

🕗 Version & Regression Information

  • This changed between versions 5.7 and 5.8

⏯ Playground Link

No response

💻 Code

https://github.com/fxdave/cuple/pull/new/typescript-issue-5-8-memory-leak

🙁 Actual behavior

$ npx tsc

<--- Last few GCs --->

[34857:0x559d92e7c000]    42329 ms: Scavenge (interleaved) 4081.2 (4090.1) -> 4078.8 (4098.6) MB, pooled: 0 MB, 5.79 / 0.00 ms  (average mu = 0.281, current mu = 0.252) allocation failure; 
[34857:0x559d92e7c000]    43481 ms: Mark-Compact (reduce) 4089.9 (4103.4) -> 4081.8 (4088.4) MB, pooled: 0 MB, 59.32 / 0.00 ms  (+ 880.5 ms in 176 steps since start of marking, biggest step 5.5 ms, walltime since start of marking 998 ms) (average mu = 0.2
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
----- Native stack trace -----

 1: 0x559d50eec8b4 node::OOMErrorHandler(char const*, v8::OOMDetails const&) [node]
 2: 0x559d5140dd34 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node]
 3: 0x559d5140de3b v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node]
 4: 0x559d5169e0ac  [node]
 5: 0x559d516a4356 v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [node]
 6: 0x559d516a4467 v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector, v8::base::TimeTicks) [node]
 7: 0x559d516b3bc4  [node]
 8: 0x559d516b6dd4  [node]
 9: 0x559d52146ba7  [node]
fish: Job 1, 'npx tsc' terminated by signal SIGABRT (Abort)

🙂 Expected behavior

$ npx tsc
(List of type errors.)

Additional information about the issue

NOTE:
It's not a node(24.4.1) issue, I tried with a different node version (node:22-bookworm from dockerhub).
The project is tiny.
I tried adding all my free rams to node (12GB) it ate it.

Steps to reproduce:

# Download this branch: https://github.com/fxdave/cuple/pull/new/typescript-issue-5-8-memory-leak
git clone -b typescript-issue-5-8-memory-leak https://github.com/fxdave/cuple.git
cd cuple

# Setup:
npm i
make build # Important!

# run npx tsc in the tests folder
cd test
npx tsc

(the code contains errors, but that shouldn't matter.)

Activity

  1. RyanCavanaugh commented on Jul 29, 2025

    @RyanCavanaugh
    Member

    I can't repro this through tsc invocations.

  2. fxdave commented on Jul 30, 2025

    @fxdave
    Author

    I'm not sure why,

    Could you please try this?:

    docker run -it --rm -w /app node:22-bookworm sh -c 'git clone -b typescript-issue-5-8-memory-leak https://github.com/fxdave/cuple.git . && npm i && make build && cd test && npx tsc'

    This is the log I get with it:

    Cloning into '.'...
    remote: Enumerating objects: 776, done.
    remote: Counting objects: 100% (309/309), done.
    remote: Compressing objects: 100% (210/210), done.
    remote: Total 776 (delta 131), reused 247 (delta 85), pack-reused 467 (from 1)
    Receiving objects: 100% (776/776), 2.22 MiB | 10.97 MiB/s, done.
    Resolving deltas: 100% (385/385), done.
    
    added 316 packages, and audited 319 packages in 5s
    
    74 packages are looking for funding
      run `npm fund` for details
    
    14 vulnerabilities (4 low, 5 moderate, 4 high, 1 critical)
    
    To address all issues, run:
      npm audit fix
    
    Run `npm audit` for details.
    npm notice
    npm notice New major version of npm available! 10.9.2 -> 11.5.1
    npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.5.1
    npm notice To update run: npm install -g npm@11.5.1
    npm notice
    make clean-if-needed
    make[1]: Entering directory '/app'
    sh -c "( test -e packages/client/dist/ && test -e packages/server/dist ) || make clean" 
    make[2]: Entering directory '/app'
    rm packages/client/tsconfig.tsbuildinfo || echo ok
    rm packages/server/tsconfig.tsbuildinfo || echo ok
    rm -rf packages/client/dist || echo ok
    rm -rf packages/server/dist || echo ok
    make[2]: Leaving directory '/app'
    make[1]: Leaving directory '/app'
    cd packages/client && npx tsc
    cd packages/server && npx tsc
    npx tsc
    
    <--- Last few GCs --->
    
    [130:0x13ffb000]    89390 ms: Mark-Compact 4049.9 (4138.6) -> 4036.8 (4141.4) MB, pooled: 0 MB, 1342.27 / 0.00 ms  (average mu = 0.069, current mu = 0.036) allocation failure; scavenge might not succeed
    [130:0x13ffb000]    91561 ms: Mark-Compact 4052.6 (4141.4) -> 4039.6 (4143.9) MB, pooled: 0 MB, 2115.61 / 0.00 ms  (average mu = 0.043, current mu = 0.025) allocation failure; scavenge might not succeed
    
    
    <--- JS stacktrace --->
    
    FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
    ----- Native stack trace -----
    
     1: 0xe16044 node::OOMErrorHandler(char const*, v8::OOMDetails const&) [node]
     2: 0x11e0dd0 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node]
     3: 0x11e10a7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node]
     4: 0x140e985  [node]
     5: 0x140e9b3  [node]
     6: 0x1427a8a  [node]
     7: 0x142ac58  [node]
     8: 0x1c90921  [node]
    
  3. RyanCavanaugh commented on Jul 30, 2025

    @RyanCavanaugh
    Member

    We need a repro that is just invoking tsc. If you have a specific environment or outer script that is needed to reproduce the issue, then you need to figure out what specifically about that is causing an issue -- we are not resourced to investigate external tools

  4. fxdave commented on Jul 31, 2025

    @fxdave
    Author

    Ryan Cavanaugh (@RyanCavanaugh) You mentioned you couldn’t reproduce the issue, which surprised me since I was able to reproduce it even in a container isolated from my environment. That’s why I provided a simple one-liner so you can quickly verify whether the memory leak exists on your end. The memory leak is not caused by any external tools, and it is really only a tsc invocation, but dependencies have to be installed first. If the leak isn’t reproducible for you, it’s hard to move forward, since the issue would appear to be specific to my current kernel, however I assume that's unlikely.

  5. RyanCavanaugh commented on Jul 31, 2025

    @RyanCavanaugh
    Member

    It's extremely rare for us to get an issue that depends on a specific environment, and extremely common for bug reports that involve "run this build script" to be an issue with the build scripts or build script runner rather than TS itself.

    The only thing I'm asking for here is that the repo be an invocation of tsc; if you have OS / npm / disk layout / other factors that are relevant, please list them, we're happy to investigate as long as we don't need to run your custom build scripts as part of that.

  6. Renegade334 commented on Jul 31, 2025

    @Renegade334
    Contributor

    This specific case hits a few edges all at once.

    • Your project is sometimes importing zod and sometimes importing zod/v4.
    • These accidentally used to map to the same .d.ts file due to the package.json top-level types field being erroneously appended to subdirectory lookups, which was addressed by Fix incorrect usage of package.json types/main in package subdirectories #60696.
    • These would still resolve to the same .d.ts definitions due to the package.json exports map, but your project is using "module": "commonjs" (ie. "moduleResolution": "node10"), which doesn't honour exports.
    • As a result, the two imports are resolving to different definition targets (v4/index.d.cts and v4/index.d.ts respectively).
    • Because of this, the same named import from zod and zod/v4 is actually two identical-looking but discrete symbols.
    • Because of this, your scripts end up running assignability checks between massive complex types from one module and massive complex types from the other module, which is resulting in a runaway instantiation chain.

    In an ideal world, the compiler should be reporting a TS2589 and aborting gracefully, but everything else is intended behaviour.

  7. fxdave commented on Aug 1, 2025

    @fxdave
    Author

    René (@Renegade334) Thanks. Indeed it ran with 30Gigs using swapfile for additional memory.

    5.7.3 ran it using 100MB (NODE_OPTIONS="--max-old-space-size=100").

    If it's not leak at least it is very inefficient on memory.

  8. Renegade334 commented on Aug 1, 2025

    @Renegade334
    Contributor

    Would suggest either using one import consistently (zod or zod/v4), or changing the module option in your tsconfigs to node16 (to enable exports maps), so that these imports resolve to the same module path.

    The commonjs module option corresponds to pre-Node v12 module behaviour; under this schema, those two module imports are resolved to different paths. This only worked for you previously due to a small bug in TypeScript's module resolver, which meant it was accidentally doing what you intended.

  9. fxdave commented on Aug 7, 2025

    @fxdave
    Author

    René (@Renegade334) Thanks for the support. If you feel like it is worth keeping the issue open for the TS2589 message, I leave it open and let you guys close it.

  10. jofflin commented on Sep 15, 2025

    @jofflin

    Wow,
    thank for clarification. That issue cost me a whole day for sure. I tried everything, including switching to tsgo, testing with different IDE's and more. Just removing all zod/v4 and replacing it with zod resolved the issue.

    Thanks!

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs More InfoThe issue still hasn't been fully clarified

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions