Skip to content

programs.direnv.enableNushellIntegration silently clobbers $env.SHELL since nushell 0.111 #9387

@wokalski

Description

@wokalski

=With programs.direnv.enableNushellIntegration = true, entering a directory that uses use flake .#X in its .envrc silently overwrites \$env.SHELL with the nix-store bash path, and never restores it after cd out. Reproducible on nushell ≥ 0.111.0.

Reproduction

.envrc

use flake .#

flake.nix

{ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
   outputs = { nixpkgs, ... }: {
     devShells.aarch64-darwin.default =
       nixpkgs.legacyPackages.aarch64-darwin.mkShell { };
   };
 }

Steps

direnv allow

echo $env.SHELL
cd /tmp
echo $env.SHELL

Root cause

Three independent design choices stack to produce a silent corruption:

  1. Nix's mkShell exports a lowercase shell env var as part of stdenv's build environment.
  2. Direnv keeps SHELL (uppercase) in its IgnoredKeys list but does not ignore lowercase shell. So direnv export json emits {"shell": "/nix/store/...-bash"} on load (and no SHELL).
  3. Nushell since PR #17558 (merged 2026-02-18, first shipped in 0.111.0) treats \$env as case-insensitive on all platforms — so load-env { shell: ... } is the same as setting \$env.SHELL.

On unload, direnv emits {"shell": null}. The hook applies it; either the slot becomes empty or falls through to the OS-level $SHELL — but it's never restored to the pre-load value, because direnv never tracked `SHELL` to begin with.

Suggested fix

In `modules/programs/direnv.nix`, drop nix-mkShell-internal lowercase keys before `load-env`. Between `into record` and `load-env`:

| reject -i SHELL? shell? shellHook? builder? out? outputs? phases? stdenv? system? name?

`-i` makes the reject case-insensitive so it covers `shell` and `SHELL` regardless of how nushell or direnv evolve. The `?` suffix on each key makes it optional (no error if absent).

Workaround (until fixed)

Set `programs.direnv.enableNushellIntegration = false` and write a custom hook in `programs.nushell.configFile` / `extraConfig` with the `reject` line above.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions