System version of command in PATH until I reload my shell

  • MacOS Big Sur
  • nix (Nix) 2.3.16
  • home-manager 22.05
  • zsh 5.8 (x86_64-apple-darwin20.0)

I have a very strange issue that’s probably best explained with an image:

Whenever I start a new shell, ruby points to the system version, not the version I installed with home-manager. However, when I run exec zsh, ruby points to the home-manager version.

I have this same problem with vim, where zsh uses the system version until I reload it. I suspect that this will be a problem for overriding any command that I already have installed.

I’m confused why this is happening, and I want to know how I can have zsh use the home-manager version automatically.

In my .zshrc, I have

source ~/.nix-profile/etc/profile.d/

In my .zshenv, I have

. /Users/fisher/.nix-profile/etc/profile.d/
export NIX_PATH=$HOME/.nix-defexpr/channels${NIX_PATH:+:}$NIX_PATH

How does your terminal start the shell?

IIRC Mac doesn’t start it as login shell, so you might have to source the vars through .zprofile.

1 Like

See here, zsh will not load your .zshrc if it’s started as a login shell, I think @NobbZ mean the opposite of what they say :wink:

I’m always confusing regular, login, non-interactive, interactive, and whatnot modes of shells… So yeah, can totally be that I mean the opposite of what I am saying.

Yeah, the modes of shells are confusing. It’s made worse since the behavior on macOS seems to be different: interactive shells are login shells by default.

I confirmed this by adding to my .zshenv,

echo "hello from .zshenv"

and adding to my .zshrc,

echo "hello from .zshrc"

The result is both are output when I open a terminal.

I dug a little deeper, and thought about what could be causing my original issue. Somehow, the commands installed through home-manager aren’t being added to my PATH, right? So I compared the PATHs before and after I reloaded the shell.

In the after picture, my custom paths are added to the beginning of PATH, so they take precedence over the default paths. But, this makes me confused, why are they added to the end of PATH in the before picture?

I see the problem now. .zshenv is sourced before /etc/zprofile. /etc/zprofile runs the commands generated by the path_helper binary:

PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Users/fisher/.gem/ruby/3.0.0/bin:/Users/fisher/bin:/Users/fisher/.cargo/bin:/Users/fisher/.local/bin:/Users/fisher/.nix-profile/bin"; export PATH;

So my nix path is being added to PATH before my system path, and it gets re-ordered by path_helper. Renaming my .zshenv to .zprofile fixed this issue, but I’m still confused on why Apple sets the PATH variable in /etc/zprofile instead of /etc/zshenv.

Looks like abandoning .zshenv in favor of .zprofile is the recommended solution, based on this write-up.

I also considered renaming /etc/zprofile to /etc/zshenv, but after reading a related Nix issue, I don’t think that would have been a good solution; it probably would have lead to things breaking after an update.

I still couldn’t find anything about Apple not using /etc/zshenv, so if anyone finds anything on that, let me know.