Should the attribute `shell` be avoided in overlays?

Defining shell in an overlay seems to produce surprising behavior. In the following example

let
  overlay = self: super: {
    myshell = self.mkShell {
      buildInputs = [ self.hello ];
    };
  };
  pkgs = import <nixpkgs> { overlays = [ overlay ]; };
in
pkgs.myshell

nix-shell works as expected, but when myshell is renamed to shell I get the following error trace:

This derivation is not meant to be built, aborting

builder for '/nix/store/92py6nlc2f27b9ddd0wppmlxc16j19d5-nix-shell.drv' failed with exit code 1
cannot build derivation '/nix/store/1v9dw56m8452vhq5gzh7pj2dxrzrsn6l-binutils-wrapper-2.35.1.drv': 1 dependencies couldn't be built
...

I originally discovered this while adding GitHub - cdepillabout/nix-cabal-example-project to my project; nix-shell works as-is, but when I changed our-shell to shell in the overlay (this diff), I get the (confusingly, different) error

error: anonymous function at /nix/store/hz2yzvaihcna6gc54mvs4c0mpwv3yqr1-source/pkgs/build-support/fetchurl/boot.nix:5:1 called with unexpected argument 'postFetch', at /nix/store/hz2yzvaihcna6gc54mvs4c0mpwv3yqr1-source/pkgs/build-support/fetchzip/default.nix:17:2

I’m a bit puzzled because I don’t see an existing shell attribute in the nixpkgs global namespace, so it doesn’t seem like I’d be clobbering anything. Not using shell is simple enough, but I’d really like to understand what’s going on here so as to avoid frustrating debugging in the future.

What an interesting error.

$ nix eval --impure --show-trace --expr "((import <nixpkgs> {}).extend (_: _: { shell = throw \"rekt\"; })).bash.outPath"
error: rekt

       … while evaluating 'getOutput'

       at /nix/store/vpcxp9a1zsv9nbhlymyha1ay6251ddfz-source/lib/attrsets.nix:489:23:

          488|   */
          489|   getOutput = output: pkg:
             |                       ^
          490|     if ! pkg ? outputSpecified || ! pkg.outputSpecified

       … from call site

       at /nix/store/vpcxp9a1zsv9nbhlymyha1ay6251ddfz-source/pkgs/build-support/bintools-wrapper/default.nix:106:11:

          105|   inherit bintools_bin libc_bin libc_dev libc_lib coreutils_bin;
          106|   shell = getBin shell + shell.shellPath or "";
             |           ^
          107|   gnugrep_bin = if nativeTools then "" else gnugrep;

       … while evaluating the attribute 'shell' of the derivation 'binutils-wrapper-2.35.2'

binutils-wrapper defines a function argument “shell” and sets it to stdenvNoCC.shell by default. Because of callPackage, the shell argument will be set to what’s in the package set, replacing the default. You could probably break a lot of packages in interesting ways by defining other generic-sounding attributes like “name” or “patches”.

3 Likes