You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
node_modules FOD hash is calibrated against one bun version — breaks with any other #49063
The Nix flake's node_modules fixed-output derivation is hash-pinned via nix/hashes.json. Those hashes are calibrated by the nix-hashes CI workflow, which runs with the bun provided by the flake's own nixpkgs input.
Downstream consumers that follow a different nixpkgs (e.g. via inputs.nixpkgs.follows = "nixpkgs" in their flake) build the FOD with a different bun version. bun install resolves and lays out node_modules differently per bun version, so the output hash changes and the FOD fails deterministically:
Verified to be deterministic, not environmental: building the same FOD separately with bun 1.3.13 and bun 1.4.2 yields exactly those two different hashes.
This means every follower that pins its own nixpkgs hits this class of failure each time either the upstream bun or theirs moves — see also #47332 (dev-shell bun drift) and #37623 (prior occurrence of a stale hash).
Steps to reproduce
From a flake with inputs.opencode.url = "github:anomalyco/opencode"; inputs.opencode.inputs.nixpkgs.follows = "nixpkgs"; where the follower's nixpkgs ships bun ≠ 1.3.13:
nix build .#packages.<system>.opencode
Suggested directions
Two complementary options:
Short term — calibrate against more than one bun. Record hashes.json per bun major version (system × bun), or pin the FOD's bun to upstream's nixpkgs version explicitly so the calibration stays valid regardless of the follower's nixpkgs.
Structural — replace the single recursive FOD with a lockfile-aware fetcher (e.g. bun2nix, which fetches packages individually using the integrity hashes already in bun.lock). That makes the FOD bun-version-agnostic by design — the current pain point generalizes to every bun bump, and bun2nix eliminates exactly this class of failure.
Happy to contribute the calibration-side change if agreed.
OpenCode version
dev at a74c472 (nix package, flake consumer)
Reacted by Psyolia, Zunway, Cai Strickland and James Carl
changed the title [-]fix(nix): node_modules FOD hash is calibrated against one bun version — breaks with any other[/-][+]node_modules FOD hash is calibrated against one bun version — breaks with any other[/+]on Sep 14, 2026
Adding a data point from a consumer that hit this on v2, because it narrows the diagnosis: the hash can differ even when the bun build is identical, so "pin the bun version" alone does not make hashes.json reproducible.
Same bun binary, same bun.lock, same fileset source, same nixpkgs version string — and still two different results:
$ nix build .#packages.x86_64-linux.node_modules_updater # fakeHash, built locally
error: hash mismatch in fixed-output derivation '...opencode-node_modules-2.0.18+dd786c6.drv':
specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
got: sha256-aVE36jaHfkvtzMyQv8ssMovGMHHgLKDk0GyxYeMOkVU=
$ nix build .#packages.x86_64-linux.default # committed hash
→ resolves from cache.nixos.org, builds fine
$ nix/hashes.json (committed, i.e. what the nix-hashes runners produced)
"x86_64-linux": "sha256-7DgxTpKv6ITKTom0mhlJNPQfdEjtEHK5P8uyCr26HZw="
The local build is self-consistent — I reproduced aVE36jaHf... on separate runs hours apart — it is just not what the calibration runners produced. So the FOD output depends on something beyond the bun version: filesystem, locale, or ordering in the canonicalize-node-modules.ts / normalize-bun-binaries.ts post-processing, none of which hashes.json records.
This is also why the nix-hashes workflow comment about native runners being required is not quite the whole story — this machine is x86_64-linux and still diverges.
I read this as strengthening the argument for the structural option in this issue: a lockfile-aware fetcher (bun2nix, using the integrity hashes already in bun.lock) produces the same bytes on every machine, whereas re-calibrating hashes.json per consumer keeps re-introducing this. Happy to help there.
Thanks for the detailed write-up and for checking that the two bun versions give two different hashes.
To restate the request: the Nix node_modules fixed-output derivation is calibrated against the bun in the flake's own pinned nixpkgs. With inputs.nixpkgs.follows, a different bun produces a different hash. You're asking for the dependency fetch to be independent of the bun version, either by recording hashes per bun version or pinning the FOD's bun, or by fetching from bun.lock with bun2nix. The current dev (v2) flake still works this way (nix/node_modules.nix plus one hash per system in nix/hashes.json), so this applies to v2 as well. Maintainers will consider it.
Activity
[-]fix(nix): node_modules FOD hash is calibrated against one bun version — breaks with any other[/-][+]node_modules FOD hash is calibrated against one bun version — breaks with any other[/+]fix(opencode): repin the node_modules FOD per our nixpkgs bun
fix(opencode): repin the node_modules FOD per our nixpkgs bun
fix(opencode): keep upstream nixpkgs so their FOD hash applies as-is
fix(opencode): keep upstream nixpkgs so their FOD hash applies as-is
fix(opencode): keep upstream nixpkgs so their FOD hash applies as-is
jerome-benoit commentedon Sep 28, 2026
Adding a data point from a consumer that hit this on
v2, because it narrows the diagnosis: the hash can differ even when the bun build is identical, so "pin the bun version" alone does not makehashes.jsonreproducible.Setup:
v2atdd786c62, consumed from a flake withso the FOD builds with the consumer's nixpkgs
bun, and that resolves to the same store path as opencode's own locked nixpkgs:Same bun binary, same
bun.lock, samefilesetsource, samenixpkgsversion string — and still two different results:The local build is self-consistent — I reproduced
aVE36jaHf...on separate runs hours apart — it is just not what the calibration runners produced. So the FOD output depends on something beyond the bun version: filesystem, locale, or ordering in thecanonicalize-node-modules.ts/normalize-bun-binaries.tspost-processing, none of whichhashes.jsonrecords.This is also why the
nix-hashesworkflow comment about native runners being required is not quite the whole story — this machine isx86_64-linuxand still diverges.I read this as strengthening the argument for the structural option in this issue: a lockfile-aware fetcher (
bun2nix, using the integrity hashes already inbun.lock) produces the same bytes on every machine, whereas re-calibratinghashes.jsonper consumer keeps re-introducing this. Happy to help there.fix(nix): drop x86_64-darwin target
fix(nix): drop x86_64-darwin target
refactor(nix): fetch dependencies from bun.lock
refactor(nix): fetch dependencies from bun.lock
refactor(nix): fetch dependencies from bun.lock
opencodejr commentedon Oct 28, 2026
Thanks for the detailed write-up and for checking that the two bun versions give two different hashes.
To restate the request: the Nix
node_modulesfixed-output derivation is calibrated against the bun in the flake's own pinned nixpkgs. Withinputs.nixpkgs.follows, a different bun produces a different hash. You're asking for the dependency fetch to be independent of the bun version, either by recording hashes per bun version or pinning the FOD's bun, or by fetching frombun.lockwith bun2nix. The currentdev(v2) flake still works this way (nix/node_modules.nixplus one hash per system innix/hashes.json), so this applies to v2 as well. Maintainers will consider it.Related issues and PRs:
bun.locknode_moduleshash reportspackageManagerrequires