Rebuilding system using niv fails in nixos 22.05

I used to fix my nixpkgs version for my notebook using niv and up until nixos-21.11 that worked out well.
I wanted to update to nixos-22.05 recently but now I get a very obscure error message which I have pasted below.

The setup I am using consists of an extra sources-dir.nix file in the nixpkgs folder generated by niv:

{ system ? builtins.currentSystem }:

  sources = import ./sources.nix {};
  pkgs = import sources.nixpkgs { inherit system; };
  lib = pkgs.lib;
  pkgs.runCommand "sources" {} (
    lib.concatStringsSep "\n" ([
      "mkdir $out"
      ++ lib.mapAttrsToList (name: source: "ln -s ${source.outPath} $out/${name}") sources

And I rebuild my system using the following bash script:

sources=$(nix-build nix/sources-dir.nix --no-out-link)
nixos-rebuild switch --target-host user@notebook --use-remote-sudo -I "$sources" -I "nixos-config=$PWD/configuration.nix"

This was shown to me by someone at the local makerspace and I have used it ever since.

I also use this to remotely rebuild various virtual machines for my password manager and so on and all of this worked out well until the 22.05 update came along.

Ever since I have updated the nixpkgs branch in niv to nixos-22.05 the rebuild command fails with the following error message:

building Nix...
building the system configuration...
error: the string '22.05' is not allowed to refer to a store path (such as '/nix/store/0qma2xzkmp0x3j6gb0936fimvqsp297g-nixpkgs-src')

       at /nix/store/363n9qpp2aibismayc93ack9kjbs1da7-sources/nixpkgs/lib/strings.nix:562:26:

          561|   */
          562|   versionOlder = v1: v2: compareVersions v2 v1 == 1;
             |                          ^
(use '--show-trace' to show detailed location information)

I have scoured the internet on and off for about a week now and I have no idea what to make of this.
The error message "foo is not allowed to refer to a store" comes up in seemingly unrelated contexts.

When I remove the -I "$sources" flag from the command and have it use my system channel instead it works. My system channel is also on 22.05

Certain ways of working with a store path as a string will store the information about the store path in the string’s context. Many nix built-ins, including compareVersions intentionally do not support strings with non-empty context.

It appears that the 22.05 version might have been extracted from a store path somehow. To find what is responsible, rerun the command with --show-trace argument.

Than you for your reply. That is definitely an interesting read.
Feels like strings with context aren’t actually strings at all but a different type entirely tho.

I re-ran the command with --show-trace and the following is the result of that:

Looks like the string being compared is system.stateVersion:

Looking at the option definition, I would not expect it to have a context, though:

  1. nixpkgs/version.nix at e34ee08ec5ef13adeadddde1e78f408374d65713 · NixOS/nixpkgs · GitHub
  2. nixpkgs/version.nix at e34ee08ec5ef13adeadddde1e78f408374d65713 · NixOS/nixpkgs · GitHub
  3. nixpkgs/trivial.nix at e34ee08ec5ef13adeadddde1e78f408374d65713 · NixOS/nixpkgs · GitHub

Are you perhaps setting it manually to something other than just plain string? The best practice is just keeping it a fixed to a version nixos-generate-config put in your configuration and only bumping it after reading release notes and noting the steps needed to migrate the state for services you use.

Good catch. I would not have seen that in that huge trace, but I had no idea what to look for either.

Unfortunately I do not set system.stateVersion anywhere other than what was generated when I set my system up initially.

I basically copied my system config to a folder in my home directory, added niv and the scripts from the first post and have been running the shell script whenever I wanted to change anything. I have added a bit more fluff to the script irl, like connecting to a vpn before deploying servers and such but that should not be relevant here.

Maybe the error stops showing up when I set system.stateVersion to 22.05?
I will try that on a new VM

EDIT: Nope, still appears.
I should probably make a reproducible example

I have managed to isolate the problem into a git repository:

Running NIX_PATH="$sources::nixos-config=$PWD/configuration.nix" /nix/store/iakj2nchjqlxhrpgxnshlsqcg3rrw762-nixos-option/bin/nixos-option system.stateVersion, the value is actually set correctly.

But looking at the trace some more, it actually fails in the docs build. And those will not pick up the stateVersion from your config to allow the docs build be better cached.

Though, even then, I do not see where it could be getting the string context:

It seems to work when I prepend nixpkgs=$HOME/Projects/nixpkgs to NIX_PATH, even with the same commit as the one pinned by niv.

Looking at it in Nix REPL, the output builtins.readFile appears to inherit string context from the path:

nix-repl> :t "${import ./nix/sources-dir.nix {}}"
a string with context

nix-repl> :t (import ./nix/sources.nix {}).nixpkgs.outPath
a string with context

nix-repl> :t builtins.readFile "${import ./nix/sources-dir.nix {}}/nixpkgs/.version"
a string with context

nix-repl> :t builtins.readFile "/home/jtojnar/Projects/nixpkgs/.version"
a string

So I guess you can apply the following workaround.

--- a/nix/sources-dir.nix
+++ b/nix/sources-dir.nix
@@ -9,6 +9,6 @@ in
     lib.concatStringsSep "\n" ([
       "mkdir $out"
-      ++ lib.mapAttrsToList (name: source: "ln -s ${source.outPath} $out/${name}") sources
+      ++ lib.mapAttrsToList (name: source: "ln -s ${builtins.unsafeDiscardStringContext source.outPath} $out/${name}") sources
\ No newline at end of file
1 Like