Change in behavior of builtins.path between 2.91.1 and 2.92.0 #776

Open
opened 2025-03-28 08:46:57 +00:00 by jakehamilton · 5 comments

Describe the bug

I am trying to perform a pure evaluation of an arbitrary expression which imports a store path. This store path has a known path and hash (it is already in the store) and this functionality worked on Lix 2.91.1. However, after updating to 2.92.0 attempting to do so yields an error like the following:

nix eval --expr "builtins.path { path = \"$store_path\"; sha256 = \"$store_path_hash\"; }"
error:
       … while calling the 'path' builtin
         at «string»:1:1:
            1| builtins.path { path = "/nix/store/lplzlyk8ldz821dl6pmlhk3md1ms69md-config"; sha256 = "sha256:18fnzrc26890rnizn1gzkmgw52rl2z3xd0cdwihw4vi9h8m36hbv"; }
             | ^

       … while adding path '/nix/store/lplzlyk8ldz821dl6pmlhk3md1ms69md-config'

       error: access to absolute path '/nix/store/lplzlyk8ldz821dl6pmlhk3md1ms69md-config' is forbidden in pure eval mode (use '--impure' to override)

Steps To Reproduce

  1. Start by adding a directory to the Nix store: store_path=$(nix-store --add-fixed --recursive sha256 $(pwd))
  2. Then query the store for the entry's hash: store_path_hash=$(nix-store --query $store_path --hash)
  3. Run a pure eval on an expression that tries to access the store path using builtins.path: nix eval --expr "builtins.path { path = \"$store_path\"; sha256 = \"$store_path_hash\"; }"
  4. The error appears on Lix 2.92.0, but not Lix 2.91.1

Expected behavior

I can see either this expression working or failing as acceptable, so long as it is consistent in Lix over the future. My initial thought is that this is likely an unintended change in functionality.

nix --version output

nix (Lix, like Nix) 2.92.0
System type: x86_64-linux
Additional system types: aarch64-linux, i686-linux
Features: gc, signed-caches
System configuration file: /etc/nix/nix.conf
User configuration files: /home/short/.config/nix/nix.conf:/etc/xdg/nix/nix.conf:/home/short/.nix-profile/etc/xdg/nix/nix.conf:/home/short/.local/state/nix/profile/etc/xdg/nix/nix.conf:/home/short/.local/state/nix/profile/etc/xdg/nix/nix.conf:/etc/profiles/per-user/short/etc/xdg/nix/nix.conf:/nix/var/nix/profiles/default/etc/xdg/nix/nix.conf:/run/current-system/sw/etc/xdg/nix/nix.conf:/nix/store/ys1zqxjyiczkny9bfi1f7i6clm1z39cd-gnome-settings-daemon-47.2/etc/xdg/nix/nix.conf
Store directory: /nix/store
State directory: /nix/var/nix
Data directory: /nix/store/vyfqgaip2hbylhhm1lci1zfvxv6a5g28-lix-2.92.0/share

Additional context

It seems like this issue may be in some way related to Issue 402. I have also found just today that the following modification to the steps mentioned above does work on Lix 2.92.0:

store_path=$(nix-store --add-fixed --recursive sha256 $(pwd))

store_path_hash=$(nix-store --query $store_path --hash)

store_path_name=$(basename $(pwd))

nix eval --expr "builtins.path { path = \"$store_path\"; sha256 = \"$store_path_hash\"; name = \"$store_path_name\"; }"

It wasn't intuitive for me to need to pass name to this call, but it was mentioned on Matrix that this may be required.

## Describe the bug I am trying to perform a pure evaluation of an arbitrary expression which imports a store path. This store path has a known path and hash (it is already in the store) and this functionality worked on Lix 2.91.1. However, after updating to 2.92.0 attempting to do so yields an error like the following: ``` nix eval --expr "builtins.path { path = \"$store_path\"; sha256 = \"$store_path_hash\"; }" error: … while calling the 'path' builtin at «string»:1:1: 1| builtins.path { path = "/nix/store/lplzlyk8ldz821dl6pmlhk3md1ms69md-config"; sha256 = "sha256:18fnzrc26890rnizn1gzkmgw52rl2z3xd0cdwihw4vi9h8m36hbv"; } | ^ … while adding path '/nix/store/lplzlyk8ldz821dl6pmlhk3md1ms69md-config' error: access to absolute path '/nix/store/lplzlyk8ldz821dl6pmlhk3md1ms69md-config' is forbidden in pure eval mode (use '--impure' to override) ``` ## Steps To Reproduce 1. Start by adding a directory to the Nix store: `store_path=$(nix-store --add-fixed --recursive sha256 $(pwd))` 2. Then query the store for the entry's hash: `store_path_hash=$(nix-store --query $store_path --hash)` 3. Run a pure eval on an expression that tries to access the store path using `builtins.path`: `nix eval --expr "builtins.path { path = \"$store_path\"; sha256 = \"$store_path_hash\"; }"` 4. The error appears on Lix 2.92.0, but not Lix 2.91.1 ## Expected behavior I can see either this expression working or failing as acceptable, so long as it is consistent in Lix over the future. My initial thought is that this is likely an unintended change in functionality. ## `nix --version` output ``` nix (Lix, like Nix) 2.92.0 System type: x86_64-linux Additional system types: aarch64-linux, i686-linux Features: gc, signed-caches System configuration file: /etc/nix/nix.conf User configuration files: /home/short/.config/nix/nix.conf:/etc/xdg/nix/nix.conf:/home/short/.nix-profile/etc/xdg/nix/nix.conf:/home/short/.local/state/nix/profile/etc/xdg/nix/nix.conf:/home/short/.local/state/nix/profile/etc/xdg/nix/nix.conf:/etc/profiles/per-user/short/etc/xdg/nix/nix.conf:/nix/var/nix/profiles/default/etc/xdg/nix/nix.conf:/run/current-system/sw/etc/xdg/nix/nix.conf:/nix/store/ys1zqxjyiczkny9bfi1f7i6clm1z39cd-gnome-settings-daemon-47.2/etc/xdg/nix/nix.conf Store directory: /nix/store State directory: /nix/var/nix Data directory: /nix/store/vyfqgaip2hbylhhm1lci1zfvxv6a5g28-lix-2.92.0/share ``` ## Additional context It seems like this issue may be in some way related to [Issue 402](https://git.lix.systems/lix-project/lix/issues/402). I have also found just today that the following modification to the steps mentioned above _does_ work on Lix 2.92.0: ```shell store_path=$(nix-store --add-fixed --recursive sha256 $(pwd)) store_path_hash=$(nix-store --query $store_path --hash) store_path_name=$(basename $(pwd)) nix eval --expr "builtins.path { path = \"$store_path\"; sha256 = \"$store_path_hash\"; name = \"$store_path_name\"; }" ``` It wasn't intuitive for me to need to pass `name` to this call, but it was mentioned on Matrix that this may be required.
Owner

This is the flake purity fix in 2.92.0 probably?

This is the flake purity fix in 2.92.0 probably?
Owner

Anyway I think the expression you give here would produce /nix/store/hash-hash-name ? Not confident of that fact, but pretty sure. And that's likely the root cause here: the expression you give is not a no-op.

We might want to take from this that we should improve the diagnostic in builtins.path for this case to say that it was trying to do a copy because it was missing the name parameter. And maybe also document the pure eval semantics of it.

Anyway I think the expression you give here would produce /nix/store/hash-hash-name ? Not confident of that fact, but pretty sure. And that's likely the root cause here: the expression you give is *not* a no-op. We might want to take from this that we should improve the diagnostic in builtins.path for this case to say that it was trying to do a copy because it was missing the name parameter. And maybe also document the pure eval semantics of it.
Member

Yes, this is a consequence the purity fix (I bisected to commit 8db8ac9a67 to be precise). However I think the observed behaviour is a bug since the builtins.path call is pure due to having a hash specified. (In fact it doesn't fail if the target path is already in the store.)

Yes, this is a consequence the purity fix (I bisected to commit 8db8ac9a671e7210c7e312522eb346f78ed89c86 to be precise). However I think the observed behaviour is a bug since the `builtins.path` call is pure due to having a hash specified. (In fact it doesn't fail if the target path is already in the store.)
Owner

Yeah, hmmm. But the usage here is probably incorrect, since you really do want to give a name so nix doesn't cause pointless copies that have two hashes in them. Maybe that should generate a diagnostic.

Yeah, hmmm. But the usage here is probably incorrect, since you really do want to give a name so nix doesn't cause pointless copies that have two hashes in them. Maybe that should generate a diagnostic.
Author

@jade you are indeed correct that it ended up with a weird double-hash name! I had never seen that before and it makes sense given your description. I would like to be able to access fixed paths without having to deal with extra steps, but with the addition of name I do have things working properly again.

@jade you are indeed correct that it ended up with a weird double-hash name! I had never seen that before and it makes sense given your description. I _would_ like to be able to access fixed paths without having to deal with extra steps, but with the addition of `name` I do have things working properly again.
Sign in to join this conversation.
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lix-project/lix#776
No description provided.