I recently discovered that launchd on macOS provides an initial, default $PATH to new terminal windows that is not the default path set by macOS at log in, but instead is produced by launchd according to (presumably) its own internal logic — without changes ever having been made via either launchctl or any .plist file that I could find.
This is the case whether using the Terminal.app distributed by Apple, or a third-party terminal such as Alacritty.app.
The default path on macOS at log in, as can be verified with sysctl -n user.cs_path, is
/usr/bin:/bin:/usr/sbin:/sbin
But when I placed echo $PATH on the first line of ~/.zshenv, which is sourced before /etc/zprofile and any other shell configuration file, I was seeing an entirely different $PATH when opening a new window in Alacritty:
/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin
Which I verified to be coming from launchd by searching the output of launchctl dumpstate:
pid/72911 = {
type = pid
originator = /Applications/Alacritty.app
creator = alacritty[72911]
...
environment = {
PATH => /usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin
...
}
...
}
After restarting Alacritty, with only one window and one instance of the shell the same echo command produced:
/usr/bin:/bin:/usr/sbin:/sbin
Which is what it should be. But then, opening the default Terminal.app, I get
/usr/bin:/bin
Which is, again, not the OS default.
This doesn’t necessarily affect my ability to use the shell because I can set $PATH in .zshenv or .zprofile to whatever I’d like, but it does require that I override the $PATH that launchd sets if I wish to control search order. In fact, what launchd is doing makes controlling search order crucial because there is apparently no guarantee that the initial $PATH handed to the shell will be consistent.
Does anybody know why launchd is providing an inconsistent $PATH? Is there any rhyme or reason to what it decides to include or not include in the $PATH that it provides to every shell created with every new terminal window, and varying it by terminal application?
Again, I have never
- issued
launchctl setenv PATH <path> - issued either
sudo launchctl config user <path>orconfig system <path> - modified any
.plistfile anywhere (or found any that set thePathEnvironmentVariablekey).
I am running macOS Sequoia 15.4 (24E248) on an M2 MacBook Pro, using the stock Zsh shell.
The closest answer I could find mentions that launchd manipulates the default $PATH, but the author doesn’t specify how or why.
Update 1
For the stock Terminal app, launchctl dumpstate is showing
pid/45557 = {
type = pid
originator = /System/Applications/Utilities/Terminal.app
creator = Terminal[45557]
...
environment = {
PATH => /usr/bin:/bin:/usr/sbin:/sbin
...
}
...
}
Which is indeed the correct, default $PATH. However, for the stock Terminal app, an echo $PATH statement on the first line of .zshenv continues to result in the truncated
/usr/bin:/bin
Update 2
The developers working on Alacritty have told me that they do not touch the $PATH variable.
Update 3
With echo $PATH as the first line in .zshenv producing
/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin
in Alacritty, and
/usr/bin:/bin
in Terminal, subsequently executing
/usr/bin/env -i /bin/zsh -l -osourcetrace
per Gairfowl’s suggestion (see comments) shows that same echo command outputting a completely different $PATH in both Alacritty and Terminal:
+/Users/Me/.zshenv:1> <sourcetrace> # line 1
/bin:/usr/bin:/usr/ucb:/usr/local/bin # line 2 `echo $PATH`
There is no /usr/ucb directory or file, hidden or not, that I could find. But given that a Google search for “ucb” tells me it is a reference to “University of California, Berkeley” (and that the output is from env -i zsh), could it be Zsh itself is manipulating the initial $PATH? And then either it or something else in macOS is inconsistently transforming /usr/ucb into one of these not-configured paths before completing echo $PATH on the first line of .zshenv, and sometimes informing launchd of the change (causing it to appear in the launchctl dumpstate output)?
Note that those two lines from the env output are printed before /etc/zprofile is sourced, thus Apple’s path_helper utility is not yet in play.
I should point out that in all my examples thus far the shell has been consistently in both login and interactive states, verified with setopt.
