"not allowed to refer to a store path" error

The following code doesn’t really make practical sense… but humor me as it is a minimal example I have come up with to demonstrate an error I’m running into:

  services.nginx = {
    enable = true;
    virtualHosts.localhost = {
      locations."${pkgs.coreutils}".alias = pkgs.writeText "test.txt" "this is a test";
    };
  };

And the error:

~> nixos-rebuild build
building Nix...
building the system configuration...
error: the string '/nix/store/9v78r3afqy9xn9zwdj9wfys6sk3vc01d-coreutils-8.31' is not allowed to refer to a store path (such as '!out!/nix/store/ymygvc86dda288xv5fcii5hgnlsrp640-coreutils-8.31.drv')
(use '--show-trace' to show detailed location information)

Is anyone able to explain to me exactly what this means?

2 Likes

It means the string has a context, and it’s being used somewhere where strings are not allowed to have contexts. The string provided as the “such as” is the first context entry here.

AIUI string contexts allow strings to carry information such as the derivations they came from, which is preserved when concatenating strings. This is used to calculate derivation dependencies. In this particular case, it’s saying you’re not allowed to use a string derived from a derivation as a services.nginx.virtualHosts.localhost.locations key.

3 Likes

Thanks @lilyball that answers the question perfectly! @zimbatm had recently mentioned string context as a reason why nix was a cool language so it’s interesting to see this error.

For bonus points, and to satisfy my curiosity, can anyone tell me why attribute keys can’t hold any string context?

This happens for every builtin that calls EvalState::forceStringNoCtx. For example builtins.fromJSON, builtins.fromTOML, builtins.fetchGit, import, builtins.getEnv, builtins.placeholder. builtins.hashFile, … Some attributes on the derivation such as system, outputHash*, outputs. Basically anything that doesn’t output either a derivation or a string again.

In that specific case, it seems like attrset keys are also not allowed to hold a context:

nix-repl> :l <nixpkgs>
Added 11298 variables.

nix-repl> { "${pkgs.coreutils}" = 3; }
error: the string '/nix/store/d7hlkykjjqs3f200jnmjm1y2hzgvbqa8-coreutils-8.31' is not allowed to refer to a store path (such as '!out!/nix/store/pvhv8cm3g8hn8prjjiw3agqbycr6jbr6-coreutils-8.31.drv')

You can cheat it by using builtins.unsafeDiscardStringContext:

nix-repl> { "${builtins.unsafeDiscardStringContext pkgs.coreutils}" = 3; }
{ "/nix/store/d7hlkykjjqs3f200jnmjm1y2hzgvbqa8-coreutils-8.31" = 3; }

But since the context is not propagated, the store path might not exist on your system though. So make sure it’s referred to it in another place as well.

6 Likes

The next question is: is there a specific reason attribute keys don’t allow strings with context? I assume this is a performance thing?

My guess is attrset keys aren’t stored as Nix strings, and in this case the context would be discarded, which is unexpected.

1 Like