You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
venv: activate.fish breaks prompt (prints directory) due to "echo 'exit $old_status' | ." line #140006
. is the source builtin, but fish resolves a function ahead of a builtin for an undecorated command, so a function . shadows it even inside a pipe. Every prompt render then pipes exit $old_status into that function instead of sourcing. When the function lists the directory (dot-style navigation plugins do exactly this), the prompt prints a directory listing on every command. The status restore also breaks.
Minimal reproduction (fish), confirmed on fish 4.1.2 (the reported version) and 4.7.1 against a venv from CPython main:
python3 -m venv /tmp/venv-gh140006
function . ; ls ; end# stand-in for any plugin or config that shadows '.'
source /tmp/venv-gh140006/bin/activate.fish
# every prompt from here on runs your `.` function instead of `source`,# so the directory gets listed after each command
The override only runs when VIRTUAL_ENV_DISABLE_PROMPT is unset, which is why a default setup hides it. tide (sets it here) and starship (sets it here) both disable the venv prompt, so their users never reach this code. The symptom needs the override active and . shadowed together.
The fix forces the builtins so no user function intercepts the line:
builtinecho"exit $old_status"|builtin source -
fish runs a builtin-decorated command as a builtin directly, bypassing any shadowing function. I verified the fix on fish 4.1.2 and 4.7.1 with ., source, and echo all shadowed: the status restores and nothing leaks.
The linked PR gh-144558 no longer exists (its URL returns 404 while neighboring numbers resolve), so no fix is open. I will open a PR that hardens the prompt override against shadowed builtins, with a regression test. Once it lands, @atagtm can confirm against the updated script.
Activity
dr-carlos commentedon Feb 5, 2026
Not entirely sure what this means, could you provide an example?
I haven't been able to reproduce this on fish 4.1.2 or the latest fish (4.3.3)
gaborbernat commentedon Jun 5, 2026
I found the root cause: a user-defined
function .(orfunction source) that shadows fish'ssourcebuiltin.The venv prompt override restores
$statusfor the wrapped prompt with this line:.is thesourcebuiltin, but fish resolves a function ahead of a builtin for an undecorated command, so afunction .shadows it even inside a pipe. Every prompt render then pipesexit $old_statusinto that function instead of sourcing. When the function lists the directory (dot-style navigation plugins do exactly this), the prompt prints a directory listing on every command. The status restore also breaks.Minimal reproduction (fish), confirmed on fish 4.1.2 (the reported version) and 4.7.1 against a venv from CPython
main:The override only runs when
VIRTUAL_ENV_DISABLE_PROMPTis unset, which is why a default setup hides it. tide (sets it here) and starship (sets it here) both disable the venv prompt, so their users never reach this code. The symptom needs the override active and.shadowed together.The fix forces the builtins so no user function intercepts the line:
fish runs a
builtin-decorated command as a builtin directly, bypassing any shadowing function. I verified the fix on fish 4.1.2 and 4.7.1 with.,source, andechoall shadowed: the status restores and nothing leaks.The linked PR gh-144558 no longer exists (its URL returns 404 while neighboring numbers resolve), so no fix is open. I will open a PR that hardens the prompt override against shadowed builtins, with a regression test. Once it lands, @atagtm can confirm against the updated script.
gh-140006: Harden fish prompt against shadowed builtins (#150936)
pythongh-140006: Harden fish prompt against shadowed builtins (python…