Skip to content

error: path <...> is not valid when copying from local binary cache #15641

@ius

Description

@ius

Describe the bug

I'm seeing error: path <x> is not valid when attempting to copy from a local binary cache (ie. nix copy --all --from file://). I can't easily reproduce it on another machine, but I do have a couple of data points which I think should suffice.

Note there's a related (closed) issue at #9052. Over there @a-h seemed to experience the same issue as I'm seeing which I suspect to be a different bug than the one originally reported.

Crucially, this bug manifests when copying from a local binary cache. As one does in 2026 I've asked Claude and it claims to have identified the bug. Being unfamiliar with the Nix codebase/C++ I can't easily tell whether it's right but the parts I do follow make sense to me.

These two comments are relevant:
#9052 (comment)
#9052 (comment)

Note this remark by @a-h:

the copy operation looks like it's working through the alphabetic ordering of the paths, instead of following the dependency graph order (as the recursive verification does).

Claude analysis

Claims 1 and 3 below seem fair to me, 2 would be the root cause and I don't understand the internals well enough to tell whether it really makes sense.

(Verbatim Claude Sonnet output follows)

LocalBinaryCacheStore::queryAllValidPaths() returns x-named paths
("<hash>-x") because only the hash part is known from .narinfo
filenames. This caused three interacting failures:

1. dstStore.queryValidPaths(x-named) finds nothing in the local SQLite
   database, so ALL paths appear missing — even those already present
   under their real names.

2. srcStore.topoSortPaths(x-named) calls queryPathInfo(<hash>-x) which
   correctly resolves narinfos and returns real-named references, but 
   topoSort then checks items.count(real-named-ref) against a set of
   x-named items — always 0 — so no dependency edges are found and the 
   sort produces an arbitrary ordering.

3. RemoteStore::addMultipleToStore() (protocol >= 1.32) sends paths to
   the daemon in pathsToCopy order. The daemon processes them
   sequentially with addToStore(); when a dependent arrives before its 
   reference, registerValidPaths() calls queryValidPathId() on a path
   not yet in SQLite and throws "path '...' is not valid".

Other backends like ssh:// work because RemoteStore::queryAllValidPaths()
fetches real names from the remote daemon's SQLite, so topoSortPaths
correctly orders them.

Fix: after building pathsToCopy (which already carries real destination
path names and references), re-sort it topologically using those real
names. This produces the correct dependency order regardless of what
srcStore.topoSortPaths returned.

Metadata

Was able to trigger on Nix 2.34.5.


Add 👍 to issues you find important.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions