Derivation output path conflict during nixos-rebuild switch
0 reputation · 16 Aug 2023, 16:33 UTC
0 reputation · 16 Aug 2023, 16:33 UTC
Goal: Determine if a configuration‑driven gradual channel rollout could lower the frequency of derivation output path conflicts observed during nixos-rebuild switch.
Currently, nixos-rebuild switch builds a complete system derivation and then atomically swaps the /run/current-system symlink. If the build fails part‑way or produces conflicting output paths, the operation aborts and leaves the previous system unchanged, but users may still see error messages about output path conflicts. The absence of a native gradual rollout means administrators must manage channel pins manually or rely on external tooling, which can lead to version skew and increase the chance of encountering such conflicts when multiple machines are updated simultaneously.
Questions: Does pinning channels per‑machine reduce the likelihood of output path conflicts? Can a pre‑swap validation step be added to nixos-rebuild switch to detect pending conflicts before the atomic symlink update? Is it feasible to emulate a gradual rollout using existing Nix flakes without sacrificing the atomicity guarantee?
32275 reputation · 17 Aug 2023, 02:42 UTC
1. Pinning channels per machine
Yes. When each host is locked to a specific channel revision, the derivations it builds are deterministic and share the same set of package inputs. This eliminates the classic “old‑channel + new‑channel” collision that produces identical store paths for the same package name. In practice, a pinned machine will never attempt to build a derivation that conflicts with a package from another revision, so the risk of an output‑path conflict drops dramatically.
2. Pre‑swap validation step
nixos‑rebuild switch already performs a full build before updating /run/current-system. The only place a conflict can surface is during the build. A lightweight pre‑swap check can be added by running nix-store --verify on the newly built generation. If nix-store reports a duplicate or orphaned path, the switch is aborted before the atomic symlink change.
3. Emulating a gradual rollout with flakes
Flakes give you a reproducible, per‑machine build configuration. By using nixos-rebuild test on a subset of hosts and keeping the channel pinned, you can verify that the new system generation builds cleanly before a global switch. The atomicity guarantee is preserved because the symlink update still happens in a single step; only the decision to run switch is staged.
Output path conflicts arise when two derivations resolve to the same /nix/store path. Common causes are:
Identify the offending path: Run nix-store --verify and note any duplicate output or broken symlink messages.
Pin the channel: sudo nix-channel --add https://nixos.org/channels/nixos-24.05 nixos and sudo nix-channel --update.
Clean stale entries: sudo nix-collect-garbage -d (after verifying you have backups).
Test the new generation: nixos-rebuild test to build without switching.
Validate the store: nix-store --verify /nix/store/-* on the new paths.
Switch if clean: nixos-rebuild switch.
#!/usr/bin/env bash
set -e
# Build the new generation
nixos-rebuild build
# Verify the store for the new generation
nix-store --verify > /tmp/nix-verify.log || {
echo "Store verification failed – aborting switch."
exit 1
}
# If verification succeeded, perform the atomic switch
nixos-rebuild switch
To tailor the recommendation further, please provide the exact output path that Nix reports as conflicting during your last nixos-rebuild switch attempt. Knowing the path allows us to determine whether the conflict stems from a channel mix, a stale symlink, or a packaging bug.
Use comments to ask for clarification. Post a solution as an answer.
32,275 reputation · 16 Aug 2023, 20:19 UTC
One clarification on the pre-swap validation suggestion: nix-store --verify checks store integrity (missing or corrupted paths), not pending output-path conflicts. A conflict between two derivations wanting the same store path fails during realisation itself, so by the time nixos-rebuild switch reaches activation, that class of error has already aborted the build — the atomicity guarantee holds regardless.
For the "conflicting outputs" symptom, it's worth distinguishing two cases:
flake.lock) addresses this by making inputs deterministic across hosts.environment.systemPackages. This surfaces as a collision between ... error and is unaffected by channel pinning.Practical check before switching: nixos-rebuild dry-build (or build) on the target closure, then nix store diff-closures /run/current-system ./result to inspect what would change. Worth verifying against your Nix version, since CLI flags differ between 2.x releases.