Understanding versions & update

I am trying to update my nix-os setup so that I have the latest version of cargo. I am failing and I don’t understand the situation. I have the following version:

$ cargo --version                         
cargo 1.84.1 (66221abde 2024-11-19)

This is neither the one from channel 24.11' (1.82) nor from unstable’ (1.85), according to NixOS Search.

My nix config is GitHub - Xadeck/nixos-config. As far as I can tell, I should be using the unstable channel. I have run:

$ nix flake update
$ nixos-rebuild --use-remote-sudo switch --upgrade \
  --flake ~/nixos-config#gkmtec

The part that is puzzling me is that I have the version fi want through nix shell ?!?!

$ nix-shell -p cargo --run "cargo --version" 
cargo 1.85.0 (d73d2caf9 2024-12-31)

What are the differences ? What I am missing?

Details

Nix channels with sudo:

$ sudo nix-channel --list 
nixos https://nixos.org/channels/nixos-unstable
$ sudo nix-channel --list-generations                    
   1   2025-01-10 00:34:14   
   2   2025-01-15 08:16:24   
   3   2025-03-24 08:32:42   (current)

and without:

$ nix-channel --list   
nixos https://channels.nixos.org/nixos-unstable
$ nix-channel --list-generations                     
   1   2025-01-15 08:16:35   
   2   2025-03-24 11:55:50   (current)

and the nix info:

$ nix-info -m   
 - system: `"x86_64-linux"`
 - host os: `Linux 6.12.10, NixOS, 25.05 (Warbler), 25.05.20250322.1e5b653`
 - multi-user?: `yes`
 - sandbox: `yes`
 - version: `nix-env (Nix) 2.24.12`
 - channels(root): `"nixos"`
 - nixpkgs: `/nix/store/fnc4632ncr5k5la19gp2gb255dx8pi9x-source`

You are using a flake, nix-channel stuff is not relevant for it. Your lockfile hasn’t been touched within the last 2 months (according to git).

Use nix flake update to update it, while in your local clone.

3 Likes

And the issue specifically is that the --upgrade flag upgrades your system channels, but does nothing to update your flake: nixpkgs/pkgs/os-specific/linux/nixos-rebuild/nixos-rebuild.sh at c2a1bd483499ec8c9b90c1913be59aef6f13ebb8 · NixOS/nixpkgs · GitHub

Unintuitive for sure. nixos-rebuild is currently being rewritten, nixos-rebuild-ng may already help avoid issues like this. ETA: No, it does not: nixpkgs/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/__init__.py at bc411b49876461723c419c8dacf160aa551b374d · NixOS/nixpkgs · GitHub

With that out of the way, you might also want to remove those channels. NixOS sets your nixpkgs channel to your flake input by default these days, so there’s no need to keep a channel around, and doing so risks getting your system/system+oldnix/user environments out of sync (which is what happened in your case, and caused the confusing cargo update in your shell).

I remove the channels, with and without sudo:

$ (sudo) nix-channel --remove nixos 

I also had run nix flake update. The change to flake.lock is visible in my git repo (did I post before pushing?). I still have version 1.85 via nix-shell and 1.84.1 otherwise.

I re-did the entire procedure:

$ nix flake update --flake ~/nixos-config
$ nix flake metadata
Resolved URL:  git+file:///home/xdecoret/nixos-config
Locked URL:    git+file:///home/xdecoret/nixos-config?ref=refs/heads/main&rev=35188ae7dd4d04bcdd5f55b5cc42b1d490ae611f
Description:   GKMtec
Path:          /nix/store/994rhn81jnhwcw42cdhdj68ifz25kgs2-source
Revision:      35188ae7dd4d04bcdd5f55b5cc42b1d490ae611f
Revisions:     36
Last modified: 2025-03-25 07:19:56
Fingerprint:   1142b143250f905998376442f1dd43655d5c56f689c5532b39ddf8c0d26a96d9
Inputs:
└───nixpkgs: github:NixOS/nixpkgs/1e5b653dff12029333a6546c11e108ede13052eb?narHash=sha256-G5n%2BFOXLXcRx%2B3hCJ6Rt6ZQyF1zqQ0DL0sWAMn2Nk0w%3D (2025-03-22 18:57:23)
$ nix flake check
$ nixos-rebuild --use-remote-sudo switch --flake ~/nixos-config#gkmtec 
activating the configuration...
setting up /etc...
reloading user units for xdecoret...
restarting sysinit-reactivation.target
the following new units were started: NetworkManager-dispatcher.service
Done. The new configuration is /nix/store/a5gjc08gbz6pdxqyhl4s1l4g67z8b7pf-nixos-system-gmktec-25.05.20250322.1e5b653

Still showing 1.84.1.

I don’t get a good mental model. If I delete the flake.lock and rebuild, it reproduces the same file:

$ rm -f flake.lock
$ nix flake update --flake ~/nixos-config
warning: Git tree '/home/xdecoret/nixos-config' is dirty
warning: creating lock file '/home/xdecoret/nixos-config/flake.lock': 
• Added input 'nixpkgs':
    'github:NixOS/nixpkgs/1e5b653dff12029333a6546c11e108ede13052eb?narHash=sha256-G5n%2BFOXLXcRx%2B3hCJ6Rt6ZQyF1zqQ0DL0sWAMn2Nk0w%3D' (2025-03-22)  

where does it get the particular hash for the nixos-unstable branch?

What is the difference between these two calls:

$ nix-shell -p cargo --run "cargo --version" 
cargo 1.85.0 (d73d2caf9 2024-12-31)
$ cargo --version
cargo 1.84.1 (66221abde 2024-11-19)

where does nix-shell decides to fetch cargo from? I wonder if it has a cache, so I tried nix-collect-garbage and:

nix-shell -p cargo --run "cargo --version"
these 5 paths will be fetched (0.71 MiB download, 11.76 MiB unpacked):
  /nix/store/hyp4b779nh5y4m48zvvhd4y3z1gm8hd5-file-5.46
  /nix/store/w0mv8cgqp312dcnwlc6pz9v8nkjgw4lr-gnu-config-2024-01-01
  /nix/store/zzgldw3dwyhzn7sw9cyq7d7k57h0yx46-gnumake-4.4.1
  /nix/store/9r1nl9ksiyszy4qzzg6y2gcdkca0xmhy-stdenv-linux
  /nix/store/qjb61crwqjr60mgd75z8cfx0cmjgd1i9-update-autotools-gnu-config-scripts-hook
copying path '/nix/store/w0mv8cgqp312dcnwlc6pz9v8nkjgw4lr-gnu-config-2024-01-01' from 'https://cache.nixos.org'...
copying path '/nix/store/hyp4b779nh5y4m48zvvhd4y3z1gm8hd5-file-5.46' from 'https://cache.nixos.org'...
copying path '/nix/store/zzgldw3dwyhzn7sw9cyq7d7k57h0yx46-gnumake-4.4.1' from 'https://cache.nixos.org'...
copying path '/nix/store/qjb61crwqjr60mgd75z8cfx0cmjgd1i9-update-autotools-gnu-config-scripts-hook' from 'https://cache.nixos.org'...
copying path '/nix/store/9r1nl9ksiyszy4qzzg6y2gcdkca0xmhy-stdenv-linux' from 'https://cache.nixos.org'...
cargo 1.85.0 (d73d2caf9 2024-12-31)

Nope. Still a different version than the one installed by my flake. Could it be because my configuration uses:

 nix.settings.experimental-features = ["nix-command" "flakes"];

and those are experimental? Could there be a bug?

Firstly, I checked the commit, it’s the most recent one. You’ve likely used nix-env, but let’s address your questions first.

Nix will go to GitHub - NixOS/nixpkgs: Nix Packages collection & NixOS and download the latest commit of the branch you tell it to. This happens whenever you use nix flake update, or if you recreate the lockfile from scratch.

The $PATH variable. When you use nix-shell, nix will change the $PATH variable, adding directories in /nix/store to it for every package you asked nix-shell to add.

In the former command, cargo comes from the bin dir of the cargo package that the nixpkgs in your NIX_PATH variable contains, which is set to point at your channels by default. This seems to be working just fine, nix is indeed downloading the right version of nixpkgs.

In the latter command, whatever happens to be on the $PATH defined by your system is used. NixOS should in theory define $PATH to include exactly what you configure in /etc/configuration.nix, but you can modify that variable at runtime, by e.g. changing ~/.bashrc.

Clearly, you’ve done something to add an outdated cargo your $PATH that is not controlled by NixOS.

You can use which cargo to see this, by the way, and you can echo $PATH to see what changes nix-shell makes.

Well, I’ve been using that for half a decade now, quite unlikely to be the problem.


More likely is that at some point you’ve used the nix-env command. nix-env will permanently and imperatively modify your “profile” to include whatever package you installed.

This is not automatically updated with channel updates, let alone flake updates. It has a bunch of other UX problems, too: https://stop-using-nix-env.privatevoid.net/

Soo… Uninstall anything you installed with nix-env, and your system will make sense again.

You could also have used rustup imperatively, of course, if the above isn’t the issue.

2 Likes

Thanks for the answer. It shed some lights on the various pieces. I note that nix-env should not be used. Checking history search nix-env (I use fish), I could see that I had run (following various suggestions from posts before asking here):

sudo nix-env --install --attr nixpkgs.nix
nix-env -u '*'

But that doesn’t seem to explain the situation. nix-env --query --installed returns nothing. Also, removing all rust entries from my configuration.nix and rebuilding, I had no more cargo command so I would assume I don’t have an imperatively installed version. Finally, I had checked the path and compared with other binaries:

$ which cargo
/run/current-system/sw/bin/cargo
$ which ls
/run/current-system/sw/bin/ls

That led me to your last suggestion. History of commands showed:

rustup toolchain install nightly
rustup component add rustfmt --toolchain nightly
rustup default stable

So the problem is indeed that the rustup model is sort of contradictory with nix since it installs things on its own. So I ran rustup toolchain uninstall for all toolchains, and `rustup default none’ to remove defaults. And then…

$ shell
error: rustup could not choose a version of cargo to run, because one wasn't specified explicitly, and no default is configured.
help: run 'rustup default stable' to download the latest stable release of Rust and set it as your default toolchain.

And then, epiphany. My configuration.nix only had rustup and not cargo. That’s why comparing nix-shell -p cargo and cargo didn’t make sense!

So now I added cargo to my configuration.nix and everything is consistent. Also, rustup saves states in ~/.rustup so that’s why removing/re-adding in my configuration.nix would not reset anything.

The conclusion now is that cargo and rustup packages seems to conflict a bit. Now that I have both, if I run:

$ rustup toolchain install stable
stable-x86_64-unknown-linux-gnu installed - rustc 1.85.1 (4eb161250 2025-03-15)
$ rustup default stable

I have the following interesting situation:

$ cargo --version
cargo 1.85.0 (d73d2caf9 2024-12-31)
$ rustup run stable -- cargo --version
cargo 1.85.1 (d73d2caf9 2024-12-31)
$ cargo +stable --version
error: no such command: `+stable`

	Cargo does not handle `+toolchain` directives.
	Did you mean to invoke `cargo` through `rustup` instead?

So I have to make a choice:

  1. use cargo package and be truly nix-ish with a declarative repeatable setup, but I can not use e.g. cargo +nightly fmt which can be handy.
  2. use rustup package and have multiple toolchains available, at the lost of imperative configuration.
  3. use both at the cost of running rustup run [toolchain] -- cargo ... commands when needed.

Glad things finally make sense. Thanks TLATER for the guidance.

1 Like

You can also use fenix to keep a fully declarative setup if you have more specific toolchain needs :slight_smile:

1 Like

What about running that as root?

It also returns nothing.