Skip to content

libexpr: add temp roots during evaluation to prevent GC races#446

Closed
martinjlowm wants to merge 1 commit into
DeterminateSystems:mainfrom
martinjlowm:fix/add-temp-roots-during-eval
Closed

libexpr: add temp roots during evaluation to prevent GC races#446
martinjlowm wants to merge 1 commit into
DeterminateSystems:mainfrom
martinjlowm:fix/add-temp-roots-during-eval

Conversation

@martinjlowm
Copy link
Copy Markdown

@martinjlowm martinjlowm commented May 5, 2026

Upstream NixOS#15795 - we mainly use Determinate hence the "forward"-port

Motivation

Evaluation resolves store paths (reads .drv files, computes closures, extracts output paths) without holding the GC lock or registering temp roots. This creates a race window where GC can delete .drv files between evaluation resolving them and the build phase adding its own temp roots, resulting in "No such file or directory" errors.

Add addTempRoot() calls at the key points where libexpr reads derivations from the store:

  • import: before validating and reading an imported .drv file
  • derivationStrict: before computing the FS closure and reading input derivations during derivation instantiation
  • mkSingleDerivedPathStringRaw: before reading a derivation to resolve a built path string
  • PackageInfo constructor: before reading a derivation for package metadata queries

This closes the window between evaluation and build where concurrent GC (whether from nix-collect-garbage, nh clean, or the daemon's own min-free auto-GC) could delete paths that evaluation has resolved but not yet protected.

Context

We're experiencing concurrent GC passes that regularly wipe .drv's off of disk when a concurrent process is halted during the eval phase, this leads to the following when the process gets to proceed:

error: opening file '/nix/store/...-rust_aws-smithy-protocol-test-0.63.14.drv': No such file or directory

This complements NixOS#15469

This happens for us on: nix (Nix) 2.28.3

Now, this is my first contribution to Nix itself, so I'm not aware of any potential performance penalties in extending the set of temproots at eval-time.

Evaluation resolves store paths (reads .drv files, computes closures,
extracts output paths) without holding the GC lock or registering temp
roots. This creates a race window where GC can delete .drv files
between evaluation resolving them and the build phase adding its own
temp roots, resulting in "No such file or directory" errors.

Add addTempRoot() calls at the key points where libexpr reads
derivations from the store:

- import: before validating and reading an imported .drv file
- derivationStrict: before computing the FS closure and reading
  input derivations during derivation instantiation
- mkSingleDerivedPathStringRaw: before reading a derivation to
  resolve a built path string
- PackageInfo constructor: before reading a derivation for package
  metadata queries

This closes the window between evaluation and build where concurrent
GC (whether from nix-collect-garbage, nh clean, or the daemon's own
min-free auto-GC) could delete paths that evaluation has resolved but
not yet protected.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b1265485-9387-4989-9b41-9dacf1c91087

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@martinjlowm martinjlowm closed this May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant