Repository navigation
[7.0 regression] Unbounded type relation expansion during variance computation causes OOM #64423
Description
🔎 Search Terms
typescript 7.0.2 tsc noEmit out of memorytypescript-go checker Relater recursiveTypeRelatedTo memorytypescript 7 silent typecheck hang
🕗 Version & Regression Information
The project was using TypeScript 7.0.2 when tsc --noEmit stopped returning and consumed increasing memory. We switched the primary compiler dependency to TypeScript 6.0.3 and kept 7.0.2 installed as an npm alias so we could run both versions on the same source tree and configuration. TypeScript 6.0.3 completes successfully; 7.0.2 runs out of memory under a 6 GiB virtual-address limit.
We have not bisected TypeScript 7 releases, so we cannot identify the first affected TypeScript 7 version. The original uncapped run did not complete; the bounded failure described below is reproducible.
⏯ Playground Link
No response
💻 Code
This is a private React 19/TypeScript project with TSX application code, types, E2E tests, and Vite/Playwright configuration. Relevant tsconfig.json settings (excerpt, not a standalone reproduction):
{
"compilerOptions": {
"strict": true,
"jsx": "react-jsx",
"moduleResolution": "bundler",
"skipLibCheck": true,
"composite": true,
"incremental": true,
"noEmit": true
}
}The config includes src/**/*, types/**/*, and e2e/**/*, plus config files, and excludes node_modules and the local rendering dependency. The project's typecheck script is tsc --noEmit. With dependencies installed in this private project, these commands compare both compilers on the same checkout (the alias typescript7 points to typescript@7.0.2):
node_modules/typescript/bin/tsc --noEmit --pretty false --incremental false --composite false
prlimit --as=6442450944 -- node_modules/typescript7/bin/tsc --noEmit --pretty false --incremental false --composite false
prlimit --as=6442450944 -- node_modules/typescript7/bin/tsc --noEmit --noCheck --pretty false --incremental false --composite falseBoth full-check commands disable incremental/composite mode to avoid build-cache effects. The prlimit cap prevents the native TypeScript 7 binary from exhausting the host's memory.
🙁 Actual behavior
TypeScript 7.0.2 produces no compiler progress, diagnostic, or error output while memory grows; the original uncapped run never returned. The developer also observed no compiler output even with verbose logging enabled. In a bounded run, the first output appears only when the Go runtime runs out of memory:
runtime: out of memory: cannot allocate 4194304-byte block (5082873856 in use)
fatal error: out of memory
With a 6 GiB virtual-address limit, the TypeScript 7 check exited with status 2 after about 36 seconds and roughly 4.8 GiB peak RSS (three runs). The same source tree completed under TypeScript 6.0.3 without diagnostics.
🙂 Expected behavior
The full TypeScript 7 typecheck should finish or report actionable diagnostics without exhausting available memory on a project that TypeScript 6 checks successfully. If it cannot finish, it should not silently consume memory without producing useful output.
Additional information about the issue
Environment: Linux x64, 8 available CPUs, 15 GiB physical memory, 8 GiB swap, Node.js v26.8.0-alpha.0.0.0. TypeScript 7.0.2 uses its native Linux x64 Go compiler.
Measurements used /usr/bin/time -f 'elapsed=%e max_rss_kb=%M exit=%x' with a 90-second timeout. The TypeScript 6 run had no address-space cap; the TypeScript 7 runs had a 6 GiB virtual-address cap.
| Compiler / mode | Elapsed | Peak RSS | Result |
|---|---|---|---|
| 6.0.3, full check | 47.87 s | 2,868,588 KiB | Exit 0, no diagnostics |
| 7.0.2, full check | 36.48 s | 5,026,492 KiB | Exit 2, out of memory; reproduced 3 times |
7.0.2, --noCheck |
1.42 s | 685,224 KiB | Exit 0 |
The --noCheck result suggests the expensive work happens during semantic checking. The Go traceback includes repeated github.com/microsoft/typescript-go/internal/checker.(*Relater).recursiveTypeRelatedTo frames and checker.(*Checker).getDiagnostics calls. We have not determined whether this is a leak or unusually expensive type relations. No public minimal repro is available yet because the project is private.
Activity
ahejlsberg commentedon Sep 24, 2026
Can you try TS6 with the
--stableTypeOrderingflag to see if this is related to type ordering?Amatewasu commentedon Sep 25, 2026
Sure!
Amatewasu commentedon Sep 25, 2026
I have asked a LLM to pinpoint the issue and do a repro. I have included CodeSandbox links. Here's its report:
TypeScript 7.0.2 OOM investigation — findings
Investigation of the issue reported against TypeScript 7.0.2 ("silently runs out of memory
while typechecking a project that TypeScript 6.0.3 checks successfully").
TL;DR
TS 7.0.2 (the native Go compiler,
@typescript/typescript-linux-x64) grows memory withoutbound — and without emitting any diagnostic — as soon as it checks any JSX element whose
tag resolves to a React component, in a program where
@react-three/fiber's globalReact.JSX.IntrinsicElementsaugmentation is loaded. The relation check between thecomponent and the (massively augmented)
JSX.ElementTypeunion spirals into ever-largerreduced unions until the Go runtime dies. TS 6.0.3 checks the exact same program fine.
A 5-line file reproduces it (see Minimal reproduction). Removing
either ingredient (the fiber augmentation, or the component JSX element) makes TS 7.0.2 pass.
Measurements
Machine: Linux x86_64, 15 GB RAM, Node v20/v26, memory-capped runs via
systemd-run --user --wait --collect -p MemoryMax=... -p MemorySwapMax=0 -p OOMPolicy=kill.Full project check =
tsc --noEmitwith the repositorytsconfig.json(fresh, notsconfig.tsbuildinfo).out of memory: cannot allocate 4194304-byte block (9367126016 in use)The memory growth is not "three times TS6" as the issue's bounded run suggested — it is
unbounded: the process consumes whatever cap it is given (2 GB, 6 GB, 9 GB …) and then dies
without ever printing a diagnostic.
Root cause chain
tsconfig.jsonlists"@react-three/fiber"incompilerOptions.types, and several appfiles import it directly (
Canvas,ThreeEvent,RootState,useFrame, … insrc/components/editor/editorLibCir.tsx,src/components/toolboxes/flow-configuration/flow/user-strategy/positions-map-view.tsx,src/components/editor/stock-zone-settings/*, …). Either way the package'sindex.d.tsis loaded into the program.
@react-three/fiberat the installed version10.0.0-canary.fd3335d(pinned as^10.0.0-alpha.4inpackage.json) performs a global JSX augmentation:ThreeElementsadds several hundredthree-prefixed intrinsic elements.jsx: "react-jsx", checking a component element such as<SvgIcon />(
@mui/material7.3.11) requires relating the component's type toJSX.ElementType—keyof IntrinsicElements | ComponentType<...>— which is now avery large union.
structuredTypeRelatedTo/unionOrIntersectionRelatedTo/getEffectiveConstraintOfIntersection, and inside thatgetReducedUnionTypebuilds reduced unions mapped over 32 768 constituents(
core.SameMap[...]({ptr, 0x8000, 0x8000}, ...)in the crash trace; the full-projectcrash shows the same path over 8 192 constituents), then computes
getPropertiesOfUnionOrIntersectionType/getUnionOrIntersectionPropertyon them.Memory grows without bound. This is the same stack the issue quotes
(
checker.(*Checker).checkSourceFile→getDiagnostics): the outer frames are justdeferred JSX-node checking of the file that happens to be checked when the limit hits.
repro), i.e. this is a TS 7 checker regression/deficiency, not a project pathology.
Crash stack (TS 7.0.2, minimal repro, 9 GB cap — trimmed):
Minimal reproduction
index.tsx:tsconfig.json:{ "compilerOptions": { "strict": true, "noEmit": true, "jsx": "react-jsx", "module": "esnext", "moduleResolution": "bundler", "target": "esnext", "lib": ["esnext", "dom", "dom.iterable"], "skipLibCheck": true, "esModuleInterop": true, "isolatedModules": true }, "include": ["index.tsx"] }Dependencies involved:
typescript@7.0.2,react@19.3.0/@types/react@19.3.0,@mui/material@7.3.11,@react-three/fiber@10.0.0-canary.fd3335d.Run under a memory cap (so the leak is observable instead of eating the whole machine):
Results: TS 7.0.2 is OOM-killed in ~30 s having consumed the whole cap with no output.
TS 6.0.3 on the same program finishes in ~11 s using ~1.3 GB.
Controls (all with TS 7.0.2, same cap):
import '@react-three/fiber'line<div />)<SvgIcon />,<Box sx={{...}} />)SvgIconProps/SvgIconProps['sx']without JSXSo the trigger is precisely: fiber's IntrinsicElements augmentation + a component (non-intrinsic) JSX element.
Live repro sandboxes
The same 5-line program is set up on CodeSandbox (nodebox/Node VM template). The two
sandboxes contain identical files; the only difference is the
typescriptversion inpackage.json:ts7-oom-repro(fails)ts6-control(passes)The
startscript istsc --noEmit, so the typecheck runs automatically on boot; it canbe re-run at any time from the sandbox terminal with
npm run typecheck. Expectedbehavior: the TS 7.0.2 sandbox's check grows memory without bound until the VM's OOM
killer terminates it (no diagnostics printed), while the TS 6.0.3 sandbox completes the
check cleanly with exit 0.
Amatewasu commentedon Sep 28, 2026
I've continued to ask a LLM to investigate.
Follow-up to my earlier report: removing the R3F JSX augmentation fixed the original 5-line repro, but the full project still OOMs. There is a second, independent trigger with no React and no fiber in it — just
three/tsl. Three lines are enough:Only dependencies:
typescript@7.0.2andthree@0.185.1, default-ish strict tsconfig,tsc --noEmit. TS 7.0.2 grows until the memory cap kills it (2 GiB, ~30 s, zero diagnostics). TS 6.0.3 checks the same file fine.The trigger is calling a method on a TSL node (
.div,.add,.mul, …) or passing a node-typed value into certain TSL functions (mix(float(1), ...)). Plain calls likeuv(),uv().x,texture(t, uv()),step(...),mod(...)all pass; casting the receiver toanyalso makes the repro pass. The TSL node types are built through heavily overloaded generic builders, and the crash trace is the same relater loop as the original report, running inside variance computation:Since this repro has no JSX augmentation at all, and
--stableTypeOrderingalso made TS 6 OOM earlier in this thread, both cases may share the same union-reduction/variance path rather than anything specific to the React or R3F declaration shapes.Add regression test for the effective-constraint chase during varianc…
Skip combined-constraint check while measuring variances
Add regression test for the effective-constraint chase during varianc…
[-]TypeScript 7.0.2 silently runs out of memory while typechecking a project that TypeScript 6.0.3 checks successfully[/-][+][7.0 regression] Unbounded type relation expansion during variance computation causes OOM[/+]Skip combined-constraint check while measuring variances
Add regression test for the effective-constraint chase during varianc…
Amatewasu commentedon Oct 27, 2026
I wonder why no other people are having this issue. I would have expected other people to comment on this issue?
Skip combined-constraint check while measuring variances
Add regression test for the effective-constraint chase during varianc…