build-linux fails on every workflow, before tauri build runs, at Install frontend dependencies:
npm error Cannot read properties of null (reading 'edgesOut')
Confirmed in the logs of preview jobs 5644 and 5636. No AppImage has been produced by CI since.
Root cause
Reproduced exactly, first attempt, by running the step's own commands locally on the same Node 22.23.2 the runner installs. The npm debug log gives the frame the CI output omits:
at #loadPeerSet (.../@npmcli/arborist/lib/arborist/build-ideal-tree.js:1289:38)
A null dereference in npm 10.9.8's peer-set resolver, reached through this chain:
Nothing in this repo changed to cause it. The step deleted package-lock.json before installing, so every build re-resolved the entire dependency tree against the registry — through ranges like vitest@*. Someone else published a version whose peer graph npm cannot resolve, and our CI broke. The same command succeeded fifteen hours earlier for v0.4.21.
That is the actual defect: the build was never reproducible. The crash is only how we found out. Any dependency's release could have done this, at any time, to a release build.
Fix
Linux installs with npm ci, from the committed lockfile — which is what Windows already did. macOS moves too: it kept the lockfile but still ran npm install, which is free to re-resolve. All three platforms now install identically, and none can re-resolve mid-release.
The reason the lockfile was deleted is obsolete, not ignored
2d4fce9 added the deletion "to ensure correct platform-specific bindings", which was a real problem once — rollup and esbuild ship per-platform native packages, and an older npm would record only the host's.
That no longer holds, and I checked rather than assumed:
the committed lockfile records 25 rollup platform variants
npm ci on Linux installs precisely rollup-linux-x64-gnu, rollup-linux-x64-musl and @esbuild/linux-x64
The step carries a comment saying so, and saying not to reach for deleting the lockfile again: if npm ci refuses, package.json and the lockfile have genuinely diverged, and the fix is to commit an updated lockfile.
Verification
From the tree npm ci produces:
npx tsc --noEmit — clean
npm run build — successful
npm test -- --run — 752 passed, 62 files
Also checked that the next step cannot reintroduce a fresh resolution: npx tauri --version || npm install @tauri-apps/cli is unreachable in its fallback, because @tauri-apps/cli is a pinned devDependency that npm ci installs (tauri-cli 2.11.0).
Why this goes first
#52 (the update-channel fixes) has never had its scripts execute in CI — build-linux dies before tauri build on both of its commits, which is why preview-63f282b carries only .dmg/.msi/.exe and no AppImage. Merging this unblocks validating that one for real rather than only locally.
`build-linux` fails on every workflow, before `tauri build` runs, at **Install frontend dependencies**:
```
npm error Cannot read properties of null (reading 'edgesOut')
```
Confirmed in the logs of preview jobs 5644 and 5636. No AppImage has been produced by CI since.
## Root cause
Reproduced exactly, first attempt, by running the step's own commands locally on the same Node 22.23.2 the runner installs. The npm debug log gives the frame the CI output omits:
```
at #loadPeerSet (.../@npmcli/arborist/lib/arborist/build-ideal-tree.js:1289:38)
```
A null dereference in npm 10.9.8's peer-set resolver, reached through this chain:
```
vite → @vitejs/devtools@^0.4.0 || ^0.5.0 → @vitejs/devtools-vitest@^0.5.2
→ vitest@* → @vitest/browser-playwright@5.0.0 → vitest@4.1.11 → jsdom@* → canvas@^3.2.3
```
**Nothing in this repo changed to cause it.** The step deleted `package-lock.json` before installing, so every build re-resolved the entire dependency tree against the registry — through ranges like `vitest@*`. Someone else published a version whose peer graph npm cannot resolve, and our CI broke. The same command succeeded fifteen hours earlier for v0.4.21.
That is the actual defect: **the build was never reproducible.** The crash is only how we found out. Any dependency's release could have done this, at any time, to a release build.
## Fix
Linux installs with `npm ci`, from the committed lockfile — which is what Windows already did. macOS moves too: it kept the lockfile but still ran `npm install`, which is free to re-resolve. All three platforms now install identically, and none can re-resolve mid-release.
## The reason the lockfile was deleted is obsolete, not ignored
`2d4fce9` added the deletion "to ensure correct platform-specific bindings", which was a real problem once — rollup and esbuild ship per-platform native packages, and an older npm would record only the host's.
That no longer holds, and I checked rather than assumed:
- the committed lockfile records **25** rollup platform variants
- `npm ci` on Linux installs precisely `rollup-linux-x64-gnu`, `rollup-linux-x64-musl` and `@esbuild/linux-x64`
The step carries a comment saying so, and saying not to reach for deleting the lockfile again: if `npm ci` refuses, `package.json` and the lockfile have genuinely diverged, and the fix is to commit an updated lockfile.
## Verification
From the tree `npm ci` produces:
- `npx tsc --noEmit` — clean
- `npm run build` — successful
- `npm test -- --run` — **752 passed, 62 files**
Also checked that the next step cannot reintroduce a fresh resolution: `npx tauri --version || npm install @tauri-apps/cli` is unreachable in its fallback, because `@tauri-apps/cli` is a pinned devDependency that `npm ci` installs (`tauri-cli 2.11.0`).
## Why this goes first
**#52** (the update-channel fixes) has never had its scripts execute in CI — `build-linux` dies before `tauri build` on both of its commits, which is why `preview-63f282b` carries only `.dmg`/`.msi`/`.exe` and no AppImage. Merging this unblocks validating that one for real rather than only locally.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_011YPqHpjV4EL6RNEwrRKqQm
`build-linux` fails before `tauri build` runs, on every workflow, at "Install
frontend dependencies":
npm error Cannot read properties of null (reading 'edgesOut')
Reproduced exactly on the first attempt by running the step's own commands
locally on the same Node 22.23.2 the runner installs. The debug log gives the
frame the CI output omits:
at #loadPeerSet (.../@npmcli/arborist/lib/arborist/build-ideal-tree.js:1289:38)
It is a null dereference in npm 10.9.8's peer-set resolver, reached through
vite → @vitejs/devtools → @vitejs/devtools-vitest → vitest@* →
@vitest/browser-playwright → vitest@4.1.11 → jsdom@* → canvas.
**Nothing in this repo changed to cause it.** The step deleted
`package-lock.json` before installing, so every build re-resolved the entire
tree against the registry against ranges like `vitest@*`. A dependency
published a version that produces a peer graph npm cannot resolve, and our CI
broke — the same command succeeded fifteen hours earlier for 0.4.21. That is
the real defect: the build was never reproducible, and the crash is only how we
found out.
So Linux installs with `npm ci`, from the committed lockfile, like Windows
already did. macOS moves too — it kept the lockfile but still ran `npm
install`, which is free to re-resolve; all three platforms now install
identically and none can re-resolve mid-release.
**The reason the lockfile was being deleted is obsolete, not ignored.** 2d4fce9
removed it "to ensure correct platform-specific bindings", which was a real
problem once. The committed lockfile now records 25 rollup platform variants,
and `npm ci` on Linux installs precisely rollup-linux-x64-{gnu,musl} and
@esbuild/linux-x64 — checked directly. A comment on the step says so, and says
not to reach for deleting the lockfile again: if `npm ci` refuses, package.json
and the lockfile have genuinely diverged and the fix is to commit an updated
lockfile.
Verified from the resulting tree: `tsc --noEmit` clean, `npm run build`
successful, 752 tests across 62 files passing. The `npx tauri --version ||
npm install @tauri-apps/cli` fallback in the next step cannot reintroduce a
fresh resolution — the CLI is a pinned devDependency that `npm ci` installs, so
the fallback is unreachable.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011YPqHpjV4EL6RNEwrRKqQm
jknapp
merged commit b21a568bf5 into main2026-09-03 16:41:15 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
build-linuxfails on every workflow, beforetauri buildruns, at Install frontend dependencies:Confirmed in the logs of preview jobs 5644 and 5636. No AppImage has been produced by CI since.
Root cause
Reproduced exactly, first attempt, by running the step's own commands locally on the same Node 22.23.2 the runner installs. The npm debug log gives the frame the CI output omits:
A null dereference in npm 10.9.8's peer-set resolver, reached through this chain:
Nothing in this repo changed to cause it. The step deleted
package-lock.jsonbefore installing, so every build re-resolved the entire dependency tree against the registry — through ranges likevitest@*. Someone else published a version whose peer graph npm cannot resolve, and our CI broke. The same command succeeded fifteen hours earlier for v0.4.21.That is the actual defect: the build was never reproducible. The crash is only how we found out. Any dependency's release could have done this, at any time, to a release build.
Fix
Linux installs with
npm ci, from the committed lockfile — which is what Windows already did. macOS moves too: it kept the lockfile but still rannpm install, which is free to re-resolve. All three platforms now install identically, and none can re-resolve mid-release.The reason the lockfile was deleted is obsolete, not ignored
2d4fce9added the deletion "to ensure correct platform-specific bindings", which was a real problem once — rollup and esbuild ship per-platform native packages, and an older npm would record only the host's.That no longer holds, and I checked rather than assumed:
npm cion Linux installs preciselyrollup-linux-x64-gnu,rollup-linux-x64-musland@esbuild/linux-x64The step carries a comment saying so, and saying not to reach for deleting the lockfile again: if
npm cirefuses,package.jsonand the lockfile have genuinely diverged, and the fix is to commit an updated lockfile.Verification
From the tree
npm ciproduces:npx tsc --noEmit— cleannpm run build— successfulnpm test -- --run— 752 passed, 62 filesAlso checked that the next step cannot reintroduce a fresh resolution:
npx tauri --version || npm install @tauri-apps/cliis unreachable in its fallback, because@tauri-apps/cliis a pinned devDependency thatnpm ciinstalls (tauri-cli 2.11.0).Why this goes first
#52 (the update-channel fixes) has never had its scripts execute in CI —
build-linuxdies beforetauri buildon both of its commits, which is whypreview-63f282bcarries only.dmg/.msi/.exeand no AppImage. Merging this unblocks validating that one for real rather than only locally.🤖 Generated with Claude Code
https://claude.ai/code/session_011YPqHpjV4EL6RNEwrRKqQm
`build-linux` fails before `tauri build` runs, on every workflow, at "Install frontend dependencies": npm error Cannot read properties of null (reading 'edgesOut') Reproduced exactly on the first attempt by running the step's own commands locally on the same Node 22.23.2 the runner installs. The debug log gives the frame the CI output omits: at #loadPeerSet (.../@npmcli/arborist/lib/arborist/build-ideal-tree.js:1289:38) It is a null dereference in npm 10.9.8's peer-set resolver, reached through vite → @vitejs/devtools → @vitejs/devtools-vitest → vitest@* → @vitest/browser-playwright → vitest@4.1.11 → jsdom@* → canvas. **Nothing in this repo changed to cause it.** The step deleted `package-lock.json` before installing, so every build re-resolved the entire tree against the registry against ranges like `vitest@*`. A dependency published a version that produces a peer graph npm cannot resolve, and our CI broke — the same command succeeded fifteen hours earlier for 0.4.21. That is the real defect: the build was never reproducible, and the crash is only how we found out. So Linux installs with `npm ci`, from the committed lockfile, like Windows already did. macOS moves too — it kept the lockfile but still ran `npm install`, which is free to re-resolve; all three platforms now install identically and none can re-resolve mid-release. **The reason the lockfile was being deleted is obsolete, not ignored.**2d4fce9removed it "to ensure correct platform-specific bindings", which was a real problem once. The committed lockfile now records 25 rollup platform variants, and `npm ci` on Linux installs precisely rollup-linux-x64-{gnu,musl} and @esbuild/linux-x64 — checked directly. A comment on the step says so, and says not to reach for deleting the lockfile again: if `npm ci` refuses, package.json and the lockfile have genuinely diverged and the fix is to commit an updated lockfile. Verified from the resulting tree: `tsc --noEmit` clean, `npm run build` successful, 752 tests across 62 files passing. The `npx tauri --version || npm install @tauri-apps/cli` fallback in the next step cannot reintroduce a fresh resolution — the CLI is a pinned devDependency that `npm ci` installs, so the fallback is unreachable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011YPqHpjV4EL6RNEwrRKqQm