Flake help: 'mike-nixos' does not provide attribute 'packages.x86_64-linux.default'

Hey folks, this is driving me crazy. I’m trying to setup a new harddrive with Nix, and am now trying to migrate it to a flake. I’m getting this:

[mcrowe@xps15:~/Programming/Personal/nix-os/mike-nixos]$ nix shell
warning: Git tree '/home/mcrowe/Programming/Personal/nix-os/mike-nixos' is dirty
error: flake 'git+file:///home/mcrowe/Programming/Personal/nix-os/mike-nixos' does not provide attribute 'packages.x86_64-linux.default' or 'defaultPackage.x86_64-linux'

If I do a nix flake show, I get:

[mcrowe@xps15:~/Programming/Personal/nix-os/mike-nixos]$ nix flake show
warning: Git tree '/home/mcrowe/Programming/Personal/nix-os/mike-nixos' is dirty
git+file:///home/mcrowe/Programming/Personal/nix-os/mike-nixos
├───devShells
│   ├───aarch64-darwin
error: expected a derivation

I’m trying to cobble together my preferred config based on other users examples, and I can’t seem to find the right setup. Any advice?

flake.nix: (based off misterio77 started configs by/large)

{
  description = "Mike's system configuration";

  inputs = {
    # Unstable Branch
    # nixpkgs.url = "nixpkgs/nixos-unstable";
    # nixpkgs-unstable.url = "nixpkgs/master";
    # flake-parts.url = "github:hercules-ci/flake-parts";

    # Stable Branch
    nixpkgs.url = "nixpkgs/nixos-23.05";
    nixpkgs-unstable.url = "nixpkgs/nixos-unstable";

    home-manager = {
      url = "github:nix-community/home-manager/release-23.05";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    # TODO: Add any other flake you might need
    # hardware.url = "github:nixos/nixos-hardware";
  };

  outputs = { self, nixpkgs, home-manager, ... }@inputs:
    let
      inherit (self) outputs;
      forAllSystems = nixpkgs.lib.genAttrs [
        # "aarch64-linux"
        # "i686-linux"
        "x86_64-linux"
        "aarch64-darwin"
        # "x86_64-darwin"
      ];

    in
    rec {
      # Your custom packages
      # Acessible through 'nix build', 'nix shell', etc
      packages = forAllSystems (system:
        let pkgs = nixpkgs.legacyPackages.${system};
        in { default = import ./pkgs { inherit pkgs; }; }
      );
      # Devshell for bootstrapping
      # Acessible through 'nix develop' or 'nix-shell' (legacy)
      devShells = forAllSystems (system:
        let pkgs = nixpkgs.legacyPackages.${system};
        in { default = import ./shell.nix { inherit pkgs; }; }
      );

      formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixpkgs-fmt;

      # Your custom packages and modifications, exported as overlays
      overlays = import ./overlays { inherit inputs; };
      # Reusable nixos modules you might want to export
      # These are usually stuff you would upstream into nixpkgs
      nixosModules = import ./modules/nixos;
      # Reusable home-manager modules you might want to export
      # These are usually stuff you would upstream into home-manager
      homeManagerModules = import ./modules/home-manager;

      # NixOS configuration entrypoint
      # Available through 'nixos-rebuild --flake .#your-hostname'
      nixosConfigurations = {
        xps15 = nixpkgs.lib.nixosSystem {
          specialArgs = { inherit inputs; }; # Pass flake inputs to our config
          system = "x86_64-linux";
          modules = [
            # > Our main nixos configuration file <
            ./hosts/laptop/configuration
          ];
        };
      };

      # Standalone home-manager configuration entrypoint
      # Available through 'home-manager --flake .#your-username@your-hostname'
      homeConfigurations = {
        "mcrowe@xps15" = home-manager.lib.homeManagerConfiguration {
          pkgs = nixpkgs.legacyPackages.x86_64-linux; # Home-manager requires 'pkgs' instance
          specialArgs = { inherit inputs; }; # Pass flake inputs to our config
          modules = [
            # > Our main home-manager configuration file <
            ./home-manager/home.nix
          ];
        };
      };
    };
}

My shell.nix:

{ pkgs }:

with pkgs;
mkShell {
  name = "flakeEnv";
  buildInputs = [ rnix-lsp ];
  shellHook = ''
    alias nrb="nixos-rebuild build --flake ."
    alias nrt="sudo nixos-rebuild test --flake ."
    alias nrs="sudo nixos-rebuild switch --flake ."

    alias build-laptop="nixos-rebuild switch --flake .#laptop"
  '';
}

The error seems to be within ./shell.nix, could you share that as well?

Also, devShells should be an attribute set with at least one attribute. This is where the does not provide attribute [...].default error comes from. So unless shell.nix returns a set already, you may want to wrap it like so:

in { default = import ./shell.nix { inherit pkgs; }; }

@iFreilicht – added shell.nix

Yeah ok that looks mostly fine, so wrapping the invocation as I suggested should work. Did you try that already?

OK, that got me further. I’ve updated my question with my latest code and now

Now I’m seeing:

[mcrowe@xps15:~/Programming/Personal/nix-os/mike-nixos]$ nix shell
warning: Git tree '/home/mcrowe/Programming/Personal/nix-os/mike-nixos' is dirty
error: flake output attribute 'packages.x86_64-linux.default' is not a derivation or path

Ok nice, we’re getting somewhere!

What does nix flake show give you now? Can you check if nix develop drops you into the shell defined by devShells now?

Could you also post pkgs.nix? Maybe it returns a set or list with packages? This was my setup for a while.

@iFreilicht – here it is. Strange thing is this works with nixos-rebuild:

git+file:///home/mcrowe/Programming/Personal/nix-os/mike-nixos
├───devShells
│   └───x86_64-linux
│       └───default: development environment 'flakeEnv'
├───formatter
│   └───x86_64-linux: package 'nixpkgs-fmt-1.3.0'
├───homeManagerModules: unknown
├───nixosConfigurations
│   └───xps15: NixOS configuration
├───nixosModules
├───overlays
│   ├───additions: Nixpkgs overlay
│   ├───modifications: Nixpkgs overlay
│   └───unstable-packages: Nixpkgs overlay
└───packages
    └───x86_64-linux
error: expected a derivation

Not that surprising. nixos-rebuild only uses the nixosConfiguration output, and that seems have been evaluated correctly. Could you please answer the other questions I asked as well?

Here’s my repo

nix develop drops me into a shell, yes

nix shell:

[mcrowe@xps15:~/Programming/Personal/nix-os/mike-nixos]$ nix shell
error: flake output attribute 'packages.x86_64-linux.default' is not a derivation or path

nix flake show:

[mcrowe@xps15:~/Programming/Personal/nix-os/mike-nixos]$ nix flake show
git+file:///home/mcrowe/Programming/Personal/nix-os/mike-nixos?ref=refs%2fheads%2fbeta&rev=d403edd707c36526f05cd147cdfaf91e11e05f15
├───devShells
│   └───x86_64-linux
│       └───default: development environment 'flakeEnv'
├───formatter
│   └───x86_64-linux: package 'nixpkgs-fmt-1.3.0'
├───homeManagerModules: unknown
├───nixosConfigurations
│   └───xps15: NixOS configuration
├───nixosModules
├───overlays
│   ├───additions: Nixpkgs overlay
│   ├───modifications: Nixpkgs overlay
│   └───unstable-packages: Nixpkgs overlay
└───packages
    └───x86_64-linux
error: expected a derivation

Well that’s expected when pkgs.nix is empty.
nix shell produces an ephemeral shell with the list of installables made available. By default it uses . which will use the default package of your flake which… doesn’t exist.

      packages = forAllSystems (system:
        let pkgs = nixpkgs.legacyPackages.${system};
        in { default = import ./pkgs { inherit pkgs; }; }
      );

You probably want this to be something like

      packages = forAllSystems (system:
        import ./pkgs { pkgs = nixpkgs.legacyPackages.${system}; }
      );

What @Lord-Valen said is correct. This error message:

error: flake output attribute 'packages.x86_64-linux.default' is not a derivation or path

means exactly what it says. When I said.

I was only talking about this ./shell.nix import line, not the one where you import ./pkgs. So the suggestion by @Lord-Valen is correct, you don’t need to wrap that import in a set.

So my question now would be, what do you want to happen when you type nix shell? Should this drop you into the shell you defined in shell.nix, so that nrb, nrt and nrs are available?

Oooh, thank you for clarifying! Now I understand this error.

Thanks @iFreilicht and @Lord-Valen – apologies for not quite understanding the system yet

I’m not sure what I want the default to be yet – let me work with this a bit and get back to you

1 Like

No need to apologise :slight_smile: Nix is a paradigm shift so there’s a lot to learn, and while the documentation is getting better every day, the docs team has a lot to catch up on, so sometimes you just have to ask.

Yeah, that’s my biggest miss so far. There are soooo many ways you can do something, and if you don’t understand the nix language/model, you can’t appreciate the different aspects. I’ve downloaded 4 different nix/home-manager configurations from people who have very nice layouts that appeal to me, but you can’t exactly mix/match when you are just starting out. I’ve recently found @NobbZ’s config, and man is it clean. I wish I’d started there first. I plan on refactoring my config to follow his pattern

Here are some open questions/needs I would like to eventually understand (I’m not asking for these to be answered, but more sharing how a new pretty decent linux user struggles starting with Nix):

  • How does nix repl work wrt a flake like mine and how can I use it? I think if I understood how everything is updated, it would help learning the language.
  • I think I have to build my flake first before doing a switch, but I don’t quite understand why yet
  • Can I do a sudo nixos-rebuild switch --flake ... without rebooting if I’m not changing my nixos config?
  • I like splitting my configs up (especially my nixos ones – see here) – this, however, doesn’t seem to be the convention. Why?
  • Why do you need npins with flake lock?

(I could probably write 10 more, but those are just off the top of my head).

FWIW, I’m in love now. I see the why of nix and glimpse the beauty. I need some more proficiency and time to figure out how to setup my x11 or wayland config properly, but man, this is sweet.

Basically, you can load your flake with the repl exclusive :lf command and then execute nix expressions on them.

Try this:

$ nix repl
Welcome to Nix 2.15.1. Type :? for help.

nix-repl> :lf github:drmikecrowe/mike-nixos
Added 17 variables.

nix-repl> nixosConfigurations    
{ xps15 = { ... }; }

nix-repl> nixosConfigurations.xps15.config.services.pipewire.alsa.support32Bit      
true

nix-repl> overlays
{ additions = «lambda @ /nix/store/qkg8q120zk0pvb7sydxkxd3rkbqwzlb7-source/overlays/default.nix:5:15»; modifications = «lambda @ /nix/store/qkg8q120zk0pvb7sydxkxd3rkbqwzlb7-source/overlays/default.nix:10:19»; unstable-packages = «lambda @ /nix/store/qkg8q120zk0pvb7sydxkxd3rkbqwzlb7-source/overlays/default.nix:18:23»; }

You can basically explore the whole flake, it’s just an attribute set. You can also call functions and build nixosConfigurations manually to try out whether they actually have the effect you expect. Continuing in the session from above:

nix-repl> lib = inputs.nixpkgs.lib

nix-repl> conf = lib.nixosSystem { system = "aarch64-linux"; modules = [ { services.openssh.enable = true; } ]; }

nix-repl> conf.options.services.openssh.enable.value
true

In this example, it’s important that I assign the result to a variable conf first, so only the attributes I access actually get built. If you remove the conf =, nix will basically build the whole derivation immediately.

This is also why above, it displayed nixosConfigurations as { xps15 = { ... }; }. If you wanted to see everything in the configuration at once, it would have to be built first.

Note that the semantics of variable assignment inside repl are unique to it. They don’t work like assignments in let ... in ... blocks, nor attribute sets.

I’m not 100% sure about this either, what behavior are you seeing that makes you think this?

Yes, and you can even do it if you changed your config. Many changes can be immediately effective, such as which programs you installed, or configurations for those programs (though you might have to restart the program itself for it to notice). I think a lot of services are also shut down and cleaned up automatically during a switch, but I’m not sure it works for every single one.

Not sure. I think if you get too granular it can be annoying to find where in those files you’ve set what. You could just message the people whose configs you looked at directly here on discourse, ask for their reasoning, and report back in this thread. Would be interesting to know :slight_smile:

I assume this was a typo and you wanted to ask why pinning is important in the first place?
Basically, pinning all inputs ensures that the flake is 100% reproducible. This is very helpful when you’ve made some awful mistakes like formatting the wrong disk that make it impossible to rollback to a previous generation. You can just re-install NixOS, checkout your git repo at the commit where the known-good config came from, and nixos-rebuild, and you have the exact same configuration back.

Why flake.lock was chosen as the mechanism for this is standardization and ease of use.

Previously, you had to pin inputs when importing nixpkgs like I did in my environment configuration:

{
  pkgs ? import
    (fetchTarball
      "https://github.com/NixOS/nixpkgs/archive/30d3d79b7d3607d56546dd2a6b49e156ba0ec634.tar.gz") # unstable on 2022-04-05
    { }
, stable ? import
    (fetchTarball
      "https://github.com/NixOS/nixpkgs/archive/6120ac5cd201f6cb593d1b80e861be0342495be9.tar.gz") # 21.05 on 2021-09-20
    { }

}:

This is awful, which is why most people didn’t do it and just used import <nixpkgs> { } instead.
Finding a new hash to use when you wanted to update required you to look at the correct hydra build channel, select a new hash, copy it, and insert it correctly.
You also don’t care about this information when you just read the configuration code. Which exact version is pinned doesn’t matter, you only care which branch your using, but that information isn’t visible!

With flakes, you have the configuration and the pinning information separated, and updating the inputs is as simple as running nix flake update.

Thank you @iFreilicht – that helps a ton.

Regarding npins, I got that from looking at @NobbZ’s config here

Ahh I see. Never heard of it, but it seems to be a dependency pinning tool like niv, which is quite popular.

Basically, these tools were conceived initially to help with the exact problem I outlined above, and allowed you to replace fetcher calls like

fetchTarball "https://github.com/NixOS/nixpkgs/archive/30d3d79b7d3607d56546dd2a6b49e156ba0ec634.tar.gz"

with something easier to read. In the case of npins:

npins.nixpkgs

Now, with flakes, this doesn’t make sense for something like nixpkgs anymore, and actually, while trying it out, it doesn’t seem to make a lot of sense for non-flake inputs either. I created a small flake.nix:

{
  inputs = {
    fzf-tab = {
      url = "github:Aloxaf/fzf-tab";
      flake = false; # Must be used if the repository doesn't contain a flake.nix
    };
  };

  outputs = { self, nixpkgs, fzf-tab, ... }: { };
}

And explored it in the repl:

$ nix repl
Welcome to Nix 2.15.1. Type :? for help.

nix-repl> :lf .
warning: Git tree '/Users/feuh/repos/experiments/non-flake-input' is dirty
Added 9 variables.

nix-repl> inputs.fzf-tab
{
  lastModified = 1686496455;
  lastModifiedDate = "20230611151415";
  narHash = "sha256-gvZp8P3quOtcy1Xtt1LAW1cfZ/zCtnAmnWqcwrKel6w=";
  outPath = "/nix/store/da8i9kbmx8i8n60qw8bhf99zasgwvq19-source";
  rev = "c2b4aa5ad2532cca91f23908ac7f00efb7ff09c9";
  shortRev = "c2b4aa5";
}

nix-repl> "${inputs.fzf-tab}/src"
"/nix/store/da8i9kbmx8i8n60qw8bhf99zasgwvq19-source/src"

You can see that the input contains an outPath attribute, so it gets correctly expanded in string interpolation and you can use it as the src input for derivations.

Granted, I didn’t try out everything, but it seems that this is almost the same to getting the package with npins. So I guess NoobZ has to answer that question himself.