Nix-darwin not building, how to debug?

I’m getting this error:

❯ nix build path:.\#darwinConfigurations.Endeavor.system --show-trace                                                        ~/.home-manager
error: The option `nixpkgs.checks' does not exist. Definition values:
       - In `<unknown-file>':
           {
             x86_64-linux = {
               tarball = <derivation /nix/store/jlnhsv1gc88ryi083ayk71xpamhrb2fy-nixpkgs-tarball-22.05pre20221031.1b47226.drv>;
             };
           }

       … while evaluating the attribute 'config.system.build.toplevel'

       at /nix/store/vvycl9jb2hy2fgqliw7qy3zq3y1hyicg-source/lib/modules.nix:363:9:

          362|         options = checked options;
          363|         config = checked (removeAttrs config [ "_module" ]);
             |         ^
          364|         _module = checked (config._module);

And I’m not sure how to debug. It appears to be caused by something with nix-darwin, but I’m not sure how to debug it. (I don’t have anything that is referencing x86_64-linux in my configs, so I’m not sure where that is coming from).

My flake:

{
  description = "Home Manager configuration of Spott";

  inputs = {
    # Specify the source of Home Manager and Nixpkgs.
    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-22.05-darwin";
    #nixpkgs-unstable.url = github:NixOS/nixpkgs/nixpkgs-unstable;
    #nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";

    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    darwin = {
      url = "github:lnl7/nix-darwin/master";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { nixpkgs, home-manager, darwin, ... }:
    let 
      system = "aarch64-darwin";
      #pkgs = nixpkgs;
      #pkgs = nixpkgs.legacyPackages.${system};

      /* nixpkgsConfig = {
        config = { allowUnfree = true; };
      }; */
    in {
      /* homeConfigurations.spott = home-manager.lib.homeManagerConfiguration {
        inherit pkgs;
        modules = [
          ./home.nix
        ]; */

      darwinConfigurations."Endeavor" = darwin.lib.darwinSystem {
        inherit system;
        modules = [
        ./darwin.nix
        home-manager.darwinModules.home-manager
          {
            nixpkgs = nixpkgs;
            # `home-manager` config
            home-manager.useGlobalPkgs = true;
            home-manager.useUserPackages = true;
            home-manager.users.spott = import ./home.nix;            
          }
        ];
      };
    };

    /* let
      username = "spott";
      email = "andrew.spott@submittable.com";

      config = {
        configuration = import ./home.nix;
        inherit username;
        stateVersion = "22.05";
      };
      # system = "aarch64-darwin":
      # pkgs = nixpkgs.legacyPackages.${system};
    in {
        homeConfigurations."${username}" = home-manager.lib.homeManagerConfiguration (config // {system = "aarch64-darwin";});

      #homeConfigurations.spott = home-manager.lib.homeManagerConfiguration
    }; */
}

You’re setting a configuration option called nixpkgs to the contents of the nixpkgs flake. The alphabetically first flake output is checks, which will give you:

Because you’re bascically setting:

nixpkgs = {
  checks = {more stuff nix basically ignores};
  packages = {};
  ...
};

Why is that line there?

Because I apparently didn’t understand what I was doing… I assumed that it was looking for a nixpkgs object, and was trying to pass it the one from the import… commenting out that line got me on the right path… except packages don’t seem to be installed locally now.

home-manager seems to just skip those lines now.

I’m not clear what should be there.

Heh, ok, let’s see. For the record, I don’t use nix-darwin, never owned a mac and have always had to live inside a VM when I’m forced to use one for work. Silly companies insisting on Linux VMs if they could just use non-Apple devices…

This darwin.lib.darwinSystem is just another module system, it seems to call the module system from nixpkgs, actually, except substituting its own actual modules.

The term “module” won’t mean much to you yet, so let me try to explain. Essentially, modules are the term for the place where you define your options and set their settings. A typical module used for setting options looks something like this:

{ config, lib, pkgs, ... }:{
  imports = [ ./some-other-config.nix ];
  programs.emacs.enable = true;
}

You’ve probably seen these around home manager. You’ve most likely also only seen them as separate files. They’re pretty straightforward.

But they’re actually just functions, which you can define inline as well, the imports resolution is just really convenient, and splitting files is nice.

It’s also a little over-defined. Since none of config, lib or pkgs are actually used, we could elide them all: { ... } - the ... just means “ignore other arguments”.

Furthermore, they don’t even have to be functions - if you use none of the inputs this is actually cleaner:

{
  imports = [ ./some-other-config.nix ];
  programs.emacs.enable = true;
}

Why am I telling you all of this? Well, because you’re actually defining an inline module here:

So when you ask me what you should put there, well, your configuration options!

In fact, I see you already have a darwin.nix. Transferring these options into that file is probably cleaner.

What configuration options can we actually set, then? By default, any of the options defined here: Darwin Manual

However, none of the home-manager.users options are listed there, so where do those come from? Well, that’s where the second module, home-manager.darwinModules.home-manager, comes in.

Modules can’t just set options, they also create them. For this you use an alternate syntax:

{ config, lib, ... }: {
  imports = [ ./some-other-config.nix ];

  options = {
    enableEmacs = lib.mkEnableOption "Shortcut for emacs enabling";
  };

  config = mkIf config.enableEmacs {
    programs.emacs.enable = true;
  };
}

This is a silly example of course, but how this works isn’t important as a user most of the time anyway. The important thing to take away is that modules also define options.

home-manager.darwinModules.home-manager is a module just like that one - you can also put them in variables by the way - and it defines the home-manager options. By adding it to the modules list, you can now also set those options in your other modules (such as ./darwin.nix, or the inline definition you have currently).

So what options can we set overall? All the ones from nix-darwin, as well as these: Appendix C. nix-darwin Module Options

And that’s all there is to it!


Why did you try to set nixpkgs = nixpkgs then? I guess somehow you expected this to set the nixpkgs version either home-manager or nix-darwin use. Maybe if they had an option that works that way, but they don’t.

Instead, nix-darwin simply uses the version of nixpkgs that is provided as its flake input. You currently set that like so:

Which means it already uses the nixpkgs you expect.

Home-manager in turn allows modifying this somewhat with overlays through its normal module system, but you disable that with home-manager.useGlobalPkgs = true;, instead making sure it uses exactly the same packages as nix-darwin (which I’d recommend until you have a firm grasp on this).


And in case you’re getting confused, the stuff home manager does is a completely different module system. So the stuff documented in appendix A of the home-manager docs can only be set in the home.nix that you import. home.nix in turn can’t set any of the options that darwin.nix can.

You could try to add foreign modules to the imports list of those files, of course, but that won’t work - those modules will require stuff made available by the other module system, and there will be lots of interference. This is also why nixos modules can’t simply be installed with home-manager and vice-versa, even though they’re in theory the same kind of object. It wouldn’t make any sense anyway, the files that should be produced in the end are completely different.

But that’s an aside.


That leaves one final question, why does home-manager not install packages? I have no idea!

Apparently that’s disabled by default: Appendix C. nix-darwin Module Options

You already set that to true here, though. Did you get rid of that while debugging? Anything in terms of build logs? What do you mean by “locally”? What’s in darwin.nix and home.nix?

Thanks for the all the explanation! This was super helpful for understanding modules better.

When I refer to “locally” (bad language), I am referring to packages being built and in nix-store, but .nix-profile doesn’t point to them (.nix-profile actually doesn’t point to anything, it points to /etc/profiles/…/spott/profile, which doesn’t exist). nix profile list still lists the packages that I had installed using nix-env (which are in the /nix/var tree).

I ended up giving up on nix-darwin for the moment. I’m running Ventura, which came out a week or so ago, and it feels likely that this is a bug/incompatibility in nix-darwin (I had to pin the nixpkgs and home-manager versions to 22.05, which is around when the first Ventura beta came out), so I’m going to wait for the 22.11 release of nixpkgs and hope that fixes things.

Thanks again for the help! I’m new to the nix ecosystem, and this makes me feel very welcome, even when I’m doing things I probably should understand better.

1 Like

nw, I’ve had my days of confusedly reading through nixpkgs source, happy to help newcomers pass that hurdle a bit more quickly :slight_smile:

Shout if this still fails on your next attempt