[BUG] Shell snapshot produces syntax error and broken PATH when launched from VS Code Remote-WSL with .venv/ in workspace

Resolved 💬 2 comments Opened Mar 19, 2026 by unsetfocus Closed Apr 16, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When Claude Code is launched from VS Code (Remote-WSL) in a workspace containing a .venv/ directory, the shell snapshot file (~/.claude/shell-snapshots/snapshot-bash-*.sh) is generated with two independent bugs that make every Bash tool call fail.

Bug A: Empty if/fi block (syntax error)

The snapshot contains an rg availability check with no body, which is invalid bash:

if ! (unalias rg 2>/dev/null; command -v rg) >/dev/null 2>&1; then
fi

This produces syntax error near unexpected token 'fi' on every command.

Bug B: Escaped braces in PATH (commands not found)

The snapshot writes a malformed PATH export:

export PATH=/home/user/code/project/.venv/bin:$\{PATH\}

The $\{PATH\} is never resolved, so the PATH contains only the .venv/bin directory. Basic commands (ls, env, grep) are not found.

Full broken snapshot (11 lines):

# Snapshot file
# Unset all aliases to avoid conflicts with functions
unalias -a 2>/dev/null || true
# Functions
# Shell Options
shopt -s expand_aliases
# Aliases
# Check for rg availability
if ! (unalias rg 2>/dev/null; command -v rg) >/dev/null 2>&1; then
fi
export PATH=/home/user/code/project/.venv/bin:$\{PATH\}

Compare to a working snapshot generated from an interactive terminal session: 101 lines with base64-encoded shell functions, 60+ shopt options, a full rg function body, and a fully resolved PATH.

What Should Happen?

The snapshot should:

  1. Write a valid if block body (even just true) when rg is not found, instead of an empty block
  2. Resolve ${PATH} to actual path values instead of escaping braces as $\{PATH\}
  3. Handle the non-interactive shell case gracefully: either source .bashrc in a way that bypasses the interactive guard, or capture the environment from the parent process

Error Messages/Logs

~/.claude/shell-snapshots/snapshot-bash-*.sh: line 10: syntax error near unexpected token `fi'
~/.claude/shell-snapshots/snapshot-bash-*.sh: line 10: `fi'
/bin/bash: line 1: env: command not found
/bin/bash: line 1: grep: command not found
/bin/bash: line 1: sort: command not found

Steps to Reproduce

  1. Create a Python project with a .venv/ directory in the workspace root (e.g. python3 -m venv .venv)
  2. Have a ~/.bashrc with the standard Ubuntu interactive guard at the top:

``bash
case $- in
*i*) ;;
*) return;;
esac
``

  1. Open the project in VS Code using the Remote-WSL extension
  2. Launch Claude Code from the VS Code integrated terminal (or via the VS Code Claude Code extension)
  3. Try any Bash tool call. It fails with syntax error near unexpected token 'fi'

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.79

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

WSL (Windows Subsystem for Linux)

Additional Information

bash in terminal in VS code, not plugin sidebar

Why the snapshot is minimal (11 lines vs 101):

Claude Code spawns a non-interactive bash subprocess to capture shell state. ~/.bashrc has the standard Ubuntu interactive guard (case $-) that returns immediately for non-interactive shells. None of the shell config loads. The snapshot captures almost nothing.

Bug A (empty if/fi):

The non-interactive shell skips .bashrc, so rg (ripgrep) is not available. The snapshot generator writes the if check skeleton but never fills in the body. An empty if/fi is invalid bash.

Bug B (escaped braces in PATH):

Through 6 sessions of testing I confirmed Claude Code itself injects VIRTUAL_ENV when it detects .venv/ in the workspace. It is NOT coming from VS Code or any Python extension.

Evidence: /proc/$PPID/environ does not contain VIRTUAL_ENV, but Claude Code's shell environment does.

The snapshot generator sees VIRTUAL_ENV and writes $VIRTUAL_ENV/bin:${PATH}. It then escapes the braces to $\{PATH\}, which is not valid bash variable expansion. Since .bashrc was skipped, there's no other PATH definition, leaving PATH with only .venv/bin.

Tests performed to isolate Bug B:

| Test | Result |
|------|--------|
| Remove VIRTUAL_ENV from .vscode/settings.json | Bug persists |
| Set python.terminal.activateEnvironment: false | Bug persists |
| Set python.defaultInterpreterPath: "" | Bug persists |
| Disable ms-python.python extension | PYTHONSTARTUP gone, VIRTUAL_ENV persists |
| Disable ALL 4 Python extensions | VIRTUAL_ENV still present |
| Check /proc/$PPID/environ | VIRTUAL_ENV NOT in parent process |

Conclusion: Claude Code is the sole source of VIRTUAL_ENV. No VS Code settings or extension changes can prevent this.

Current Workaround

Manually edit ~/.claude/shell-snapshots/snapshot-bash-*.sh each session:

  1. Add true inside the empty if/fi block
  2. Replace the export PATH=... line with resolved system paths

This must be done every time Claude Code is restarted from VS Code.

Related Issues

  • #19053 - Malformed PATH with escaped characters (macOS, closed)
  • #15128 - Empty PATH on Windows Git Bash
  • #9670 - Invalid syntax in rg check (same as Bug A)
  • #2824 - False positive "not in PATH" warning
  • #4999 - Malformed alias causing syntax error (closed/fixed)
  • #1872 - Syntax error with Oh My Zsh

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗