Skip to content

venv: activate.fish breaks prompt (prints directory) due to "echo 'exit $old_status' | ." line #140006

Open

Description

@atagtm

Bug report

Bug description:

python3 -m venv test
source test/bin/activate.fish

causes ls-like output on every command.

Fix in venv/scripts/common/activate.fish:

        # Output the original/"old" prompt.
        _old_fish_prompt
        # Restore the return status of the previous command.
       return $old_status

fish, version 4.1.2

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Oct 12, 2025
  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    topic-venvRelated to the venv module
    on Oct 12, 2025
  3. dr-carlos commented on Feb 5, 2026

    @dr-carlos
    Contributor

    causes ls-like output on every command.

    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)

  4. gaborbernat commented on Jun 5, 2026

    @gaborbernat
    Contributor

    I found the root cause: a user-defined function . (or function source) that shadows fish's source builtin.

    The venv prompt override restores $status for the wrapped prompt with this line:

    echo "exit $old_status" | .

    . 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:

    builtin echo "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.

  5. added a commit that references this issue on Jun 22, 2026
  6. added a commit that references this issue on Jul 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytopic-venvRelated to the venv moduletype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions