Why does `nix develop` keep pulling an unspecified recent copy of `nixpkgs`?

Hi,

I work daily with a project containing a flake which depends on nixpkgs only once (other nixpkgs inputs all follow the main nixpkgs input):

$ nix flake metadata | grep "NixOS/nixpkgs"
│   ├───nixpkgs: github:NixOS/nixpkgs/5e7591e5e8c8cddc1e9c7cad01033e6c2d560cd0?narHash=sha256-ijS1XixgnF1UW1wnsO5J7rw5li0n6SZCBQWCYSfJwXw%3D (2024-12-08 07:13:28)

Every morning, I run nix develop in the root of my project to start my work. Most of these mornings, nix develop is downloading a recent copy of nixpkgs which I suspect is nixpkgs-unstable. For example, this morning, this was shown:

$ nix develop 
[4.8/0.0 MiB DL] downloading 'https://github.com/NixOS/nixpkgs/archive/507b63021ada5fee621b6ca371c4fca9ca46f52c.tar.gz'

I suspect it is coming from nixpkgs-unstable because also this morning I happened to have this temporary error:

$ nix develop 
warning: error: unable to download 'https://api.github.com/repos/NixOS/nixpkgs/commits/nixpkgs-unstable': HTTP error 403

       response body:

       {"message":"API rate limit exceeded for <REDACTED_IPv4>. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)","documentation_url":"https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting"}; using cached version

I do not understand why a recent copy of nixpkgs is downloaded most of the mornings I run nix develop. It slows down my work and probably fills up my nix store for no apparent good reason.

  • It is clear from the output of nix flake metadata that there is no dependency on recent nixpkgs. Why does nix develop pull a recent copy of nixpkgs?
  • When running nix develop 2 times in rapid succession, the second time never triggers the issue. What cache can I clear to reproduce the issue immediately without waiting for the next morning?

Thank you for your help!

It would be tremendously helpful to get the flake source here. In case you cannot do that, a minimal example that triggers this behavior would be fine, too.

If I had to take a wild guess, I assume that nixpkgs is used in the flake without being declared in the flake inputs, so it defaults to what is in the flake registry and this in turn defaults to nixpkgs-unstable:

> nix registry list | grep nixpkgs
global flake:nixpkgs github:NixOS/nixpkgs/nixpkgs-unstable

There is probably some caching involved so it isn’t checked for every invocation but the details elude me since I find this mechanism rather confusing and dangerous and would prefer to being able to disable it altogether so it’s always an error when used in a Flake like this.

Just to clarify, as long as an entry “nixpkgs” exists in your flake registry, this will totally work (i.e. is a valid Flake) and probably display the behavior mentioned:

{
  outputs = { self, nixpkgs }:
  let
    system = "x86_64-linux";
    pkgs = nixpkgs.legacyPackages."${system}";
  in
  {
    devShells."${system}".default = pkgs.mkShell {
      buildInputs = [ pkgs.hello ];
    };
  };
}

Edit2: Seems to still add the input to my flake.lock, I’m not sure if this actually triggers the issue.

2 Likes

I agree but I need to remove the private and/or irrelevant stuff from my flake.nix. I am trying to create a minimal example but I am limited to 1 try per day since I do not know how to reproduce this more often (basically how to clear the cache responsible for that).

That said, here is my troubleshooting flake.nix so far:

{
  inputs = {
    mysystem-deployments-utils = { url = git+ssh://git@gitlab.com/myorganization/mysystem-deployments-utils?ref=troubleshooting-nix-develop; };
  };

  outputs = { self, mysystem-deployments-utils, ... }: {
    devShells.x86_64-linux.default = mysystem-deployments-utils.devShells.x86_64-linux.deployment-repository;
  };
}

It is the flake for a deployment repository (to deploy NixOS machines with NixOps) and since I have several deployment repositories, I decided to reuse the code for the dev shell and to put it in another flake: mysystem-deployments-utils.

Here is the flake.nix for mysystem-deployments-utils:

{
  description = "My System deployments utils";

  inputs = {
    nixpkgs = { url = github:NixOS/nixpkgs/nixos-24.11-small; };
    utils = { url = github:numtide/flake-utils; };
    mysystem = {
      url = git+ssh://git@gitlab.com/myorganization/mysystem?ref=refs/tags/v0.4.0;
      inputs = { nixpkgs.follows = "nixpkgs"; utils.follows = "utils"; };
    };
  };

  outputs = { self, nixpkgs, utils, mysystem, ... }:
    utils.lib.eachSystem [ "x86_64-linux" ]
      (system:
        let
          pkgs = nixpkgs.legacyPackages.${system};

          create-deployment = mysystem.packages.${system}.create-deployment;

          build-secret = mysystem.inputs.nixpkgs-myorganization.packages.${system}.build-secret;
          hash-mosquitto-password = mysystem.inputs.nixpkgs-myorganization.packages.${system}.hash-mosquitto-password;
          hash-postgresql-password = mysystem.inputs.nixpkgs-myorganization.packages.${system}.hash-postgresql-password;

          vscodeWithExtension = pkgs.vscode-with-extensions.override {
            vscode = pkgs.vscodium;
            vscodeExtensions = with pkgs.vscode-extensions; [
              bbenoist.nix
              davidanson.vscode-markdownlint
              stkb.rewrap
              streetsidesoftware.code-spell-checker
            ];
          };
        in
        {
          devShells = {

            deployment-repository = pkgs.mkShell {
              name = "mysystem-deployment-repository-shell";

              buildInputs = [
                create-deployment
                build-secret
                hash-mosquitto-password
                hash-postgresql-password
                pkgs.git
                pkgs.nixops_unstable_minimal
                pkgs.pass
                pkgs.wireguard-tools
                vscodeWithExtension
              ];
            };
          };
        }
      );
}

I also have this on my side:

$ nix registry list | grep nixpkgs
global flake:nixpkgs github:NixOS/nixpkgs/nixpkgs-unstable

Could the problem be that my main flake.nix does not specify an explicit nixpkgs input which would make nix to look for the nixpkgs input in the registry instead?

Tomorrow I could try adding an explicit input for nixpkgs such as:

{
  inputs = {
    mysystem-deployments-utils = { url = git+ssh://git@gitlab.com/myorganization/mysystem-deployments-utils?ref=troubleshooting-nix-develop; };
    nixpkgs = { follows = "mysystem-deployments-utils/nixpkgs"; };
  };

  outputs = { self, mysystem-deployments-utils, ... }: {
    devShells.x86_64-linux.default = mysystem-deployments-utils.devShells.x86_64-linux.deployment-repository;
  };
}

Disabling the global flake registry seems to help understanding the issue:

$ nix develop --flake-registry ''
error (ignored): error: cannot find flake 'flake:nixpkgs' in the flake registries

We see that Nix is trying to look for nixpkgs in the registry although I believe (not so sure now) my flake does not depend on the nixpkgs input: neither explicitly because there is no mention of nixpkgs in the inputs, nor implicitly because there is no reference of nixpkgs in my output.
My reasoning must be wrong since Nix is obviously trying to look for nixpkgs.

Anyway, after adding an explicit nixpkgs input:

nixpkgs = { follows = "mysystem-deployments-utils/nixpkgs"; };

… running nix develop --flake-registry '' produces no error so that seems to solve the issue. I will see tomorrow and in the future days.

1 Like

Any flakes it recursively depends on may also take nixpkgs as an input. If any of them don’t specify the URL and lack a flake.lock, you’ll get this behavior.

If you can share only the inputs blocks of what you’re working with solving this mystery would be much easier, and that should be pretty easy to anonymize.

That said, I find it interesting that adding an explicit nixpkgs input apparently resolves this issue. I did not know this was a feature, kinda nifty.

I have created the following minimal repositories:

You should run nix develop on the consumer repo.

You can reproduce the error output with nix develop --flake-registry ''.

I also believe it reproduces the issue. I will have to test it during the following days to be sure but I have been playing around with nix-collect-garbage to simulate one of these mornings and I could see a similar but slightly different message on the first run of nix develop following a nix-collect-garbage:

$ nix develop 
[0.0 MiB DL] copying '«github:NixOS/nixpkgs/507b63021ada5fee621b6ca371c4fca9ca46f52c»/' to the store

Commit 507b63021ada5fee621b6ca371c4fca9ca46f52c is not the commit locked in my flakes (i.e. 48d97d2812b5e3ae7b4f9380a6028eb562a67cf0).

1 Like

Yep, looks correct. It’s entirely possible that nix just refreshes the download cache with any repos listed in the flake registry, which yeah, pretty darn annoying behavior. You’d expect it to refresh any of the other random registry entries in that case, though, and it doesn’t at least IME.

At least, unless nixpkgs just happens to be the only one that updates regularly enough to be noticeable.

This is certainly annoying behavior, in either case. The download cache is refreshed every hour iirc, in case that helps. You can change this with nix configuration.

So I can confirm my test repositories fully reproduce the issue.

Here is the result from this morning (same as the previous morning):

[me@mymachine:~/dev/playground/flakes/consumer]$ git switch add-explicit-nixpkgs-input 
Switched to branch 'add-explicit-nixpkgs-input'
Your branch is up to date with 'origin/add-explicit-nixpkgs-input'.

[me@mymachine:~/dev/playground/flakes/consumer]$ nix develop 

[me@mymachine:~/dev/playground/flakes/consumer]$ exit
exit

[me@mymachine:~/dev/playground/flakes/consumer]$ git switch main 
Switched to branch 'main'
Your branch is up to date with 'origin/main'.

[me@mymachine:~/dev/playground/flakes/consumer]$ nix develop 
[0.6/42.4 MiB DL] downloading 'https://github.com/NixOS/nixpkgs/archive/fbc071e5c11e23fba50037de37268e3d8a1858eb.tar.gz'
[42.4 MiB DL] unpacking 'github:NixOS/nixpkgs/fbc071e5c11e23fba50037de37268e3d8a1858eb' into the Git cache

Adding the explicit nixpkgs input (see add-explicit-nixpkgs-input branch) does not exhibit the problem but when trying without specifying the explicit nixpkgs input (see main branch), then the problem happens and it takes a while before the shell is ready to be used.

So, the workaround/fix is now known but can anyone explain the behavior happening here?

That could be an explanation.

I have tried to reproduce the issue several times yesterday with at least 1 hour in between but I could not reproduce the issue. Do you mean the option tarball-ttl (which default to 1 hour) when you said that the “download cache is refreshed every hour”?