.yarn/README.md
This directory holds the Yarn release used by this repo (yarnPath in
.yarnrc.yml). The release file is checked in so every contributor and CI job
runs the exact same Yarn, and so we can carry small local patches when needed.
releases/yarn-4.12.0.cjs currently carries one such patch, described below.
If you bump the Yarn version, read the Upgrading Yarn section first.
JsZipImpl for the node-modules link stepTwo call sites in releases/yarn-4.12.0.cjs are modified so the
node-modules linker (and the pnpm-loose linker) construct their read-only
ZipOpenFS with customZipImplementation: ST — Yarn's pure-JS JsZipImpl —
instead of falling through to the default WASM-backed LibZipImpl:
new $f({maxOpenFiles:80,readOnlyArchives:!0})
→ new $f({maxOpenFiles:80,readOnlyArchives:!0,customZipImplementation:ST})
A comment block at the top of the .cjs file marks the file as patched and
points back here.
On the linux-arm CI test shards we run a 32-bit arm32v7 container. During
yarn install's Link step, Yarn opens up to 80 cache zips concurrently.
With LibZipImpl, each open zip is readFileSync'd into a Node Buffer
and copied again into the WASM linear memory, and every file read does a
WASM _malloc(size) for the entry. The WASM heap has to grow as a single
contiguous region of the 32-bit address space; once enough zips are resident,
the _malloc for a large entry — most often typescript/lib/typescript.js
(~9 MB inside a ~22 MB zip) — fails.
Yarn's cross-FS copyFilePromise swallows the underlying error and re-throws
a generic one, so CI shows:
YN0001: While persisting .../typescript-patch-...zip/node_modules/typescript/
EINVAL: invalid argument, copyfile '/node_modules/typescript/lib/typescript.js' -> '...'
The unmasked form (occasionally seen on pdfjs-dist) is the WASM-heap failure
string Couldn't allocate enough memory. This started failing ~1-in-3
linux-arm / test shards at Install Dependencies on 2026-04-13, after
#50692 grew the cache enough
to push the 32-bit process over the edge nondeterministically — e.g.
run 24739817558.
JsZipImpl avoids the problem entirely: it opens the zip by file descriptor,
reads only the central directory into memory, and readSyncs individual
entries into ordinary Node Buffers — no WASM heap involved. It is
read-only and path-based, which is exactly how the linker uses these archives.
There is no .yarnrc.yml setting or environment variable to select the zip
implementation (verified against the bundle), so editing the vendored release
is the only way to switch it short of re-implementing the linker in a plugin.
Upstream references: yarnpkg/berry#3972, yarnpkg/berry#6722, yarnpkg/berry#6550.
When bumping releases/yarn-*.cjs:
readOnlyArchives opens to JsZipImpl,
or exposes a config knob for the zip implementation. If so, drop this patch.maxOpenFiles:80,readOnlyArchives:!0 (the surrounding minified identifiers
will differ) and add ,customZipImplementation:<JsZipImpl symbol> — that
symbol is whatever the new bundle exports as JsZipImpl from
@yarnpkg/libzip.rm -rf node_modules spec/node_modules && node script/yarn.js install --immutable --mode=skip-build
and confirm node_modules/typescript/lib/typescript.js is byte-identical to
an unpatched install.