Summary
oxc-parser's raw-transfer parse path allocates an ArrayBuffer of BLOCK_SIZE + BLOCK_ALIGN ≈ 6 GiB for every parse buffer. On Linux this is lazily overcommitted and harmless, but on Windows (no overcommit) the full ~6 GiB is charged against the system commit limit (RAM + pagefile) at allocation time. Under ordinary memory pressure this throws:
RangeError: Array buffer allocation failed
at createBuffer (.../oxc-parser/src-js/raw-transfer/common.js:294)
at prepareRaw (.../raw-transfer/common.js)
at parseSyncRaw (.../raw-transfer/eager.js)
at parseSync (.../oxc-parser/src-js/index.js)
Where
src-js/generated/constants.js: BLOCK_SIZE = 2147483632 (~2 GiB) and BLOCK_ALIGN = 4294967296 (4 GiB); createBuffer() does new ArrayBuffer(BLOCK_SIZE + BLOCK_ALIGN) (~6 GiB). Confirmed still present in the latest release, 0.137.0; first hit on 0.135.0.
Reproduction
Windows, Node ≥ 22 (so raw transfer is enabled), when system commit-free is below ~6 GiB:
const { parseSync } = require("oxc-parser");
parseSync("x.ts", "const x = 1;", { experimentalRawTransfer: true }); // RangeError: Array buffer allocation failed
parseSync("x.ts", "const x = 1;", { experimentalRawTransfer: false }); // OK
In the wild it surfaces via knip, which enables experimentalRawTransfer on Node ≥ 22: knip crashes intermittently on Windows when other processes have consumed commit headroom, while passing when run in isolation (more commit-free).
Environment
Windows, Node v24.15.0, oxc-parser 0.135.0 and 0.137.0. 24 GB RAM, a fixed 16 GB pagefile (commit limit ~40 GB); fails when commit-free drops below ~6 GiB.
Relationship to existing issues
This appears to be the JS-binding sibling of the Rust fixed-size-allocator OOM in #19395 / #20063, which was fixed for the Rust path by switching to VirtualAlloc in #22124 (oxc 0.131.0). That fix did not touch src-js/raw-transfer/, so the Node binding still reserves the full ~6 GiB eagerly. #20513 ("Revamp allocator") mentions removing the need for raw transfer to hold a 4 GiB allocation per AST — is the Node-side createBuffer reservation covered by that work, or should it be tracked separately?
Possible fixes
Bound/shrink the raw-transfer ArrayBuffer; reserve address space and commit on demand (VirtualAlloc/mmap) for the JS buffer as #22124 did for the Rust pool; or expose an option/env to fall back to the non-raw path on memory-constrained platforms.
Related: #20513, #19395, #20063, #22124.
Summary
oxc-parser's raw-transfer parse path allocates anArrayBufferofBLOCK_SIZE + BLOCK_ALIGN≈ 6 GiB for every parse buffer. On Linux this is lazily overcommitted and harmless, but on Windows (no overcommit) the full ~6 GiB is charged against the system commit limit (RAM + pagefile) at allocation time. Under ordinary memory pressure this throws:Where
src-js/generated/constants.js:BLOCK_SIZE = 2147483632(~2 GiB) andBLOCK_ALIGN = 4294967296(4 GiB);createBuffer()doesnew ArrayBuffer(BLOCK_SIZE + BLOCK_ALIGN)(~6 GiB). Confirmed still present in the latest release, 0.137.0; first hit on 0.135.0.Reproduction
Windows, Node ≥ 22 (so raw transfer is enabled), when system commit-free is below ~6 GiB:
In the wild it surfaces via knip, which enables
experimentalRawTransferon Node ≥ 22: knip crashes intermittently on Windows when other processes have consumed commit headroom, while passing when run in isolation (more commit-free).Environment
Windows, Node v24.15.0, oxc-parser 0.135.0 and 0.137.0. 24 GB RAM, a fixed 16 GB pagefile (commit limit ~40 GB); fails when commit-free drops below ~6 GiB.
Relationship to existing issues
This appears to be the JS-binding sibling of the Rust fixed-size-allocator OOM in #19395 / #20063, which was fixed for the Rust path by switching to
VirtualAllocin #22124 (oxc 0.131.0). That fix did not touchsrc-js/raw-transfer/, so the Node binding still reserves the full ~6 GiB eagerly. #20513 ("Revamp allocator") mentions removing the need for raw transfer to hold a 4 GiB allocation per AST — is the Node-sidecreateBufferreservation covered by that work, or should it be tracked separately?Possible fixes
Bound/shrink the raw-transfer
ArrayBuffer; reserve address space and commit on demand (VirtualAlloc/mmap) for the JS buffer as #22124 did for the Rust pool; or expose an option/env to fall back to the non-raw path on memory-constrained platforms.Related: #20513, #19395, #20063, #22124.