Repository navigation
Description
Problem
scripts/update-nixpkgs-inputs.py updates the nixpkgs inputs to branch HEAD (nix flake update --refresh). For the nixos-unstable ref set that is the wrong target: branch HEAD runs days ahead of what Hydra has built and what cache.nixos.org actually serves. An update can therefore pin a revision whose binaries do not exist in the cache yet, turning the next system build into a massive source build.
This is not hypothetical: the 2026-10-30 update pinned nixpkgs-unstable at 31ecbaca before Hydra had built it, and the amd toplevel became a multi-day source build (55k derivations, thin cache coverage). See #2715 and PR #4519 for the full fallout, including the temporary overrides that had to be bisected and pinned on top of that update.
Fix: gate the unstable ref set on the Hydra channel revision
For every input whose original.ref is nixos-unstable (currently nixpkgs-unstable and nixpkgs-25), the update target is no longer branch HEAD. It is the newest revision Hydra has fully built for the channel:
GET https://hydra.nixos.org/job/nixos/unstable/tested/latest-finished(JSON, follow redirects; jobsetnixos:unstable, renamed fromnixos:trunk-combined) → takejobsetevals[0].GET https://hydra.nixos.org/eval/<id>(JSON) → target revision isjobsetevalinputs.nixpkgs.revision.- Pin each gated input to that revision in
flake.lock: rewrite itslockedentry (rev + narHash + lastModified taken from a real nix fetch of that exact revision, e.g.nix flake metadata github:NixOS/nixpkgs/<rev>) while leaving itsoriginalentry untouched, sooriginal.refstaysnixos-unstableand input discovery (this script andnix/nixpkgs-inputs.nix) keeps matching. - If an input is already at the Hydra revision, the run is a clean no-op for it and says so.
Verified live 2026-11-02: latest-finished build 351844113 (finished, status 0), eval 1830926, revision 0bb2eedc20e4739f29e8045034f2828ad7054f8f — which is exactly the revision the 2026-11-02 scheduled update run converged on by hand.
Dead ends, do not use: channels.nixos.org/<channel>/git-rev returns 404; NixOS/nixpkgs-channels has been untouched since 2021.
Fail closed
If the Hydra lookups fail, time out, or return an unexpected shape (missing fields, a revision that is not a full 40-char commit hash), the script exits non-zero with a clear message and leaves flake.lock untouched. No update is better than an uncached update.
Scope
- Only the
nixos-unstableref set is gated. The master / no-ref set keeps its current branch-HEAD behavior (the fleet procedure does not run it, and nixpkgs-master is being removed per nixpkgs: drop the nixpkgs-master input — amd should draw only from nixos-unstable (Drew directive) #3327 — its semantics are not changed here). - This changes the updater script only; it does not move any pins on main by itself.
Acceptance criteria
- For every input whose
original.refisnixos-unstable,scripts/update-nixpkgs-inputs.pypins the Hydra channel revision (latest-finishednixos:unstabletested eval's nixpkgs revision) instead of branch HEAD, rewriting only thelockedentry (rev/narHash/lastModified from a real fetch) and leavingoriginaluntouched. - An input already at the Hydra revision is a clean no-op and the run says so.
- On any Hydra lookup failure, timeout, or unexpected response shape, the script exits non-zero with a clear message and leaves flake.lock unchanged (fail closed).
- Non-unstable inputs keep the existing branch-HEAD update behavior.
Activity
fix(scripts): gate nixpkgs-unstable updates on the Hydra-cached revision
dezren39 commentedon Nov 2, 2026
Intake review
Filed by Drew with the incident evidence (#2715, PR #4519) and a live-verified Hydra revision in the body. No open PR references this issue this run. Risks: Hydra API shape drift — the fail-closed AC covers it. Suggested approach: implement the gate inside the existing update script's per-input loop, keyed on
original.ref, with a fixture test for the eval JSON parsing.— fleet monitor intake pass, 2026-11-02. Labels normalized (kind/source/status/priority/effort) and acceptance criteria appended to the body; original body preserved above the new section.