Why is my flake overlay failing?

Hello all,

I have a fairly simple situation where I’m defining an overlay in one flake and using it in another.

In the dependency flake I’ve defined a package called zlib - nb, there is already a package with the same name in nixpkgs, and put it into that flake’s overlay:

        zlib = with pkgs; callPackage ./zlib.nix {};
      in {
        packages.default = zlib;
        overlays = final: prev: { inherit zlib; };

That all builds fine and no errors there. nix eval --raw .# gives me the store path for this, /nix/store/vn36lf7ilbcnwl2bd0qpsixi7gfxkvmi-zlib. So far so good.

I then have a second flake, which imports the dependency flake, and uses its overlay to define pkgs:

  inputs = {
    nixpkgs.url = github:NixOS/nixpkgs/nixos-21.11;
    flake-utils.url = "github:numtide/flake-utils";
    zlib.url = <path to zlib flake here>;
  }
  ...
          pkgs = import nixpkgs {
            inherit system;
            overlays = [ zlib.overlays.${system} ];
          };
          packages = {
            mainPackage = with pkgs; callPackage ./main_package.nix { };
          };

where the derivation in main_package.nix lists zlib as one of its parameters.
Unfortunately it’s taking the pre-existing nixpkgs zlib instead of my new one, as I can see by looking at the store paths in nix show-derivation .#mainPackage. Am I making some elementary mistake here? I can’t see how.

Thanks!

Overlays are not system-spaced, so I’m not sure what you’re doing zlib.overlays.${system} for, nor why it’s not yelling at you when you try.

Also, when defining the overlay, you should probably be using zlib = final.callPackage ./zlib.nix {};, rather than pulling in a separate nixpkgs invocation just for zlib.

However, for the main question, of why it’s not picking up the new package, the only thing I can think of is that you defined callPackage with a let or an argument binding somehow, and it’s overriding the with pkgs;.

OK, thank you, I’m at least reassured by the fact that I’ve not misunderstood the expected behaviour.

Are you sure overlays are not system-spaced? If I do nix flake show it will show me:

< flake base >
├───overlays
│   ├───aarch64-darwin: Nixpkgs overlay
│   ├───aarch64-linux: Nixpkgs overlay
│   ├───x86_64-darwin: Nixpkgs overlay
│   └───x86_64-linux: Nixpkgs overlay
└───packages
    ├───aarch64-darwin
...

Overlays are named. Somehow you’re getting system strings as the names.

I’m using flake-utils.lib.eachDefaultSystem from "github:numtide/flake-utils";, that’s probably the reason.

Yeah, a quick check of the code says flake-utils.lib.eachDefaultSystem doesn’t know about overlays not being system-spaced. I think you might be expected to know that yourself and put them in with // outside of the call.

Is there any way you know of to examine the contents of an overlay? They don’t get expanded out in eg nix flake show.

Load it up in the repl, and examine overlay pkgs pkgs (technically wrong, but wouldn’t matter for this case).

OK, thanks, I’ll figure it out from there.

What was the solution? I’m having a very similar problem, and I’m starting to wonder if it’s the difference between packages and legacyPackages, but I’m just grasping at straws at this point.

Truth be told, overlays were never really the best solution here. It would have been better to simply override zlib in the second argument of callPackage on the consuming package. The best overlay is no overlay, in most cases.

Just to make sure I understand, you’re suggesting this?

mainPackage = with pkgs; callPackage ./main_package.nix { zlib = zlib.packages.${system}.zlib; };

While that or similar may have worked for the original problem, mine is slightly different. I’m trying to idiomatically pass packages from a different flake to my NixOS and home-manager configurations. I think the best way to do that would be to have them available via pkgs, but importing nixpkgs with the overlay hadn’t worked for me.

And I figured it out after the fact, I had to make sure I was passing the pkgs to which I had applied the overlay through all of the necessary layers with the appropriate inherit directives.

Yes, that was what I was talking about.

For your purpose, I would simply use the packages directly from inputs, passing it into the nixos and home-manager modules with specialArgs as needed. There is no rule that all packages need to be in pkgs, and it really isn’t idiomatic to put them there if they aren’t part of nixpkgs. pkgs is supposed to be an instance of nixpkgs, not a universal namespace.

That does sound like a good fix (specialArgs was the one argument to configuration.nix that I hadn’t tried yet). Is there any documentation on why pkgs should be an instance of nixpkgs, or similar design decisions or paradigms?

There isn’t really a lot of documentation on best practices or paradigms with nix, unfortunately. A general rule most everyone does agree on is that it’s best not to use an overlay when another approach would suffice. Most things people think to use overlays for can be done with:

  • Separate variables passed through specialArgs or _module.args.
  • *.package options in nixos or home-manager.
  • Writing more complex expressions directly at the usage site, or in a let.

This is partly a performance concern, as overlays have a fairly high cost, since they need to essentially “rewire” the entirety of nixpkgs. It’s also simply a matter of sensibility: why invent a convoluted way to pass a variable around when a straightforward one exists?