Help with ‘nix-shell’ uses a nested list in attribute ‘buildInputs’

Could someone please help me re-write this flake? I’m getting this message

`Dependency of package ‘nix-shell’ uses a nested list in attribute ‘buildInputs’. This is deprecated as of Nixpkgs release 26.05, and support will be removed in a future nixpkgs release.`

This is the kind of flake I’m using.

{
  description = "A basic flake with a shell";
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/25.11";
    systems.url = "github:nix-systems/default";
    flake-utils = {
      url = "github:numtide/flake-utils";
      inputs.systems.follows = "systems";
    };
  };

  outputs =
    { nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        devShells.default = pkgs.mkShell {
          nativeBuildInputs = [ pkgs.bashInteractive ];
          buildInputs = with pkgs; [
            R
            quarto
            chromium
            pandoc
            texlive.combined.scheme-medium
            rstudio
            (with rPackages; [
              quarto
              tidyverse
            ])
          ];
        };
      }
    );
}

I believe the error comes from the (with rPackages…) part. I thought I could do something like the following, but it doesn’t work, it doesn’t like the second with.

buildInputs = with pkgs; [
            R
            quarto
            chromium
            pandoc
            texlive.combined.scheme-full
            rstudio 
            ] ++ 
            with pkgs.rPackages; [
              quarto
              tidyverse
            ]
          ];

I tried wrapping the second section in parentheses, but then it complains about a missing ; Could someone help me please? (Also, any general comments on the flake structure are appreciated. I’ve been copying and pasting for years.)

Cheers

Your suspicion is right, and the second version should work once parenthesisized.

Though even better is to just not use with.

Also you might want to prefer packages over *Inputs. Your complete buildInputs list looks as if it is usually better tailored to the nativeBuildInputs list.

And to avoid this confusion in the first place, packages is recommended for mkShell.

If I do

buildInputs = with pkgs; [
            R
            quarto
            chromium
            pandoc
            texlive.combined.scheme-medium
            rstudio 
          ] ++
            (with pkgs.rPackages; [
              quarto
              tidyverse
            ])
          ];

I get unexpected ], expecting ;. If I put a semicolon there, it complains that it wasn’t expecting one.

I’d like to avoid the repetition, because in most flakes I have many rPackages.

Are you saying I should move everything to nativeBuildInputs? I’m sorry, but I don’t know what you mean to use packages instead of Inputs.

Thanks for your help.

Please look at your code, you will see it.

Not *Inputs! packages!

Everywhere I try to put the semicolon it complains. I’ve been using nixos for a year and a half now, but the syntax is so opaque.

I really don’t know what that means.

1 Like

This message is usually telling you to remove a ], not add a ;.

An easy check is that the number of [s should always equal the number of ]s in any expression.

2 Likes

Thank you very much!

-buildInputs = with pkgs; [
+packages = with pkgs; [
             R
             quarto
             chromium
             pandoc
             texlive.combined.scheme-medium
             rstudio 
           ] ++
             (with pkgs.rPackages; [
               quarto
               tidyverse
-            ])
-          ];
+            ]);

And maybe you want to take a loot at the attrValues { inherit …; } pattern to avoid the repition and with alike.

2 Likes

That’s clear, thanks. Where can I learn about the attrValues { inherit …; } stuff. Maybe an example?

3 Likes

This works nicely and seems clean. Anything else? I do appreciate your time and input, thanks.

{
  description = "A basic flake with a shell";
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    systems.url = "github:nix-systems/default";
    flake-utils = {
      url = "github:numtide/flake-utils";
      inputs.systems.follows = "systems";
    };
  };

  outputs =
    { nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        devShells.default = pkgs.mkShell {
          nativeBuildInputs = [ pkgs.bashInteractive ];
          packages = builtins.attrValues {
            inherit (pkgs)
              R
              quarto
              chromium
              pandoc
              rstudio
              ;
            inherit (pkgs.texlive.combined) scheme-medium;
            inherit (pkgs.rPackages)
              tidyverse
              ;
          };
        };
      }
    );
}

packages is the same as nativeBuildInputs in mkShell. And you shouldn’t need to add bashInteractive explicitly.

3 Likes

Also consider using an LSP for editing nix files, they’ll make syntax errors a little easier to see and understand:

Personally I use the former, but the latter is definitely seeing more active development. I’m considering trying out nixd again since some features I was looking for have been added.

Just since you’re calling the syntax opaque; I find it no more opaque than any other programming language, but good tooling definitely helps.

1 Like

Sorry, I know it’s just me. For some reason I just have trouble grokking the nix language. TBF, I don’t use it much, so that’s on me. My main languages now are R, Python and Haskell, all of which seemed so clear and natural from the get go. Again, it’s just personal.

I didn’t realize that nil was the lsp for nix, lol. I had looked for one in my Mason (neovim) list, and it wasn’t obvious. Anyway, I’ve installed in now, thanks!

1 Like

I just ran into this myself and sweet Lord Jesus et al. I’d be curious how the humans that write nix think of these examples. But first, did AI distill this correctly?

The warning in this specific flake.nix comes from how the rPackages are being included inside the buildInputs list.

In Nix, [ ... ] always creates a list. By writing (with rPackages; [ quarto tidyverse ]) inside the existing buildInputs list, you are creating a list within a list. In Python terms, you essentially wrote ['R', 'quarto', ['quarto', 'tidyverse']] instead of a flat list. Nixpkgs now throws a deprecation warning when it encounters this nested structure in dependencies.

example one:

devShells.default = pkgs.mkShell {
  nativeBuildInputs = [ pkgs.bashInteractive ]; # don't need per waffle8946  
  # The ++ operator merges these two flat lists into one
  # rename "buildInputs" to "packages" per NobbZ
  buildInputs = with pkgs; [
    R
    quarto
    chromium
    pandoc
    texlive.combined.scheme-medium
    rstudio
  ] ++ (with pkgs.rPackages; [
    quarto
    tidyverse
  ]);
};

example two:

devShells.default = pkgs.mkShell {
  nativeBuildInputs = [ pkgs.bashInteractive ]; # don't need per waffle8946
  # rename "buildInputs" to "packages" per NobbZ
  buildInputs = with pkgs; [
    R
    quarto
    chromium
    pandoc
    texlive.combined.scheme-medium
    rstudio
    rPackages.quarto
    rPackages.tidyverse
  ];
};

No, the LLM is just throwing bullshit around. ++ concatenates lists. Your examples don’t result in any nesting, you can try it out in the repl:

nix-repl> attrset = { foo = "bar"; }
Updated attrset.

nix-repl> [ "one" "two" ] ++ (with attrset; [ foo ])
[
  "one"
  "two"
  "bar"
]

with isn’t the issue, you made some other mistake. Without seeing your original code it’s impossible to know how you ended up with a nested list (unless you mean your current examples aren’t working, in which case it must be that one of the “packages” you’re using aren’t actually a package).

If you’re going to cross-reference LLM answers, please give us at least as much context as the LLM. We don’t have crystal balls, though at least we won’t lie to you if we don’t have enough context. The answers the LLM gives you in turn are almost useless to us (and apparently to you).


I would suggest that you simply don’t use with anywhere. It’s arguably not hard to understand what with does, but it trips up newcomers quite often. It anyway leads to confusing scoping (particularly with nested with), and makes static analysis harder, so it’s generally discouraged. Yes, there are many examples of it being used basically everywhere, but not all code (and especially not in nixpkgs) you see online is perfect.

For package lists, I’ve started using lib.attrValues as a substitute:

devShells.default = pkgs.mkShell {
  nativeBuildInputs = lib.attrValues { inherit (pkgs) bashInteractive; }; # don't need per waffle8946
  # rename "buildInputs" to "packages" per NobbZ
  buildInputs = lib.attrValues {
    inherit (pkgs)
      R
      quarto
      chromium
      pandoc
      texlive.combined.scheme-medium
      rstudio;

    inherit (pkgs.rPackages)
      tidyverse;

    # Since we already have a `quarto` from `pkgs`, we need to 
    # deduplicate the attrset names; this should alert you to the
    # fact that you're *probably* doing something wrong, double
    # check that you do in fact need both the top-level *and*
    # `rPackages` quarto.
    quarto' = pkgs.rPackages.quarto;
  };
};

The inherit keyword is also often misunderstood by newcomers, in fairness, but at least it’s not as ambiguous. For the record, inherit takes a key/value pair from another attrset and inserts it into the one being built. This has nothing to do with the magical “inheritance” you see in object-oriented languages (which is why some newcomers end up being confused), it’s just copying explicitly listed key/value pairs.

See again in the repl:

nix-repl> attrset = { foo = "bar"; bar = "foo"; }
Updated attrset.

nix-repl> { inherit (attrset) foo; }
{ foo = "bar"; }

Combine that with lib.attrValues, which just turns an attrset into the list of all its attributes’ values, and you can import stuff from pkgs into a list while pretending that you’re working with attrsets, giving you access to a lot of nice nix language features.


Incidentally, your code is a great example of a situation where with is super confusing. If you wrote for example:

buildInputs = with pkgs; with pkgs.rPackages [
  quarto
];

… which instance of quarto would that resolve to? The rPackages or pkgs one? This may seem contrived, but it’s not difficult to end up in that situation if you have a slightly larger file.

2 Likes

You don’t. The rPackages one isn’t necessary.

2 Likes

Ah, I was being unclear - I ran into this error message in my own flake unrelated to R. Now, I sniffed around and got close to the offending line in my own flake but it’s all gobbledygook sometimes, ya know? In any case, Gemini got me out of my bind and I was curious how the model would answer @biscotty’s first post having been fed the code therein. The code I posted was its two proposed fixes. Thanks @TLATER - always insightful