[Bug] tmux pane spawning fails in GitBash with tmux enabled

Status Closed — not planned
Reported on v2.1.34
Maintainer reply None cached
Activity 14 comments · opened Feb 6, 2026 · closed Apr 14, 2026

Bug Description
can't swapn tmux pane running in GitBash with tmux enable

Environment Info

  • Platform: win32
  • Terminal: tmux + alacritty + windows 11
  • Version: 2.1.34
  • Feedback ID: 55b5668b-4554-444f-9e3c-619fad0790d5

Errors

[{"error":"Error: [TmuxBackend] Failed to get pane count for #session_name:#window_index (exit 1): can't find session: #session_name\n    at getCurrentWindowPaneCount (B:/~BUN/root/claude.exe:2026:837)\n    at async createTeammatePaneWithLeader (B:/~BUN/root/claude.exe:2029:496)\n    at async createTeammatePaneInSwarmView (B:/~BUN/root/claude.exe:2025:16560)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-02-06T12:56:51.559Z"},{"error":"Error: Could not determine pane count for current window\n    at createTeammatePaneWithLeader (B:/~BUN/root/claude.exe:2029:523)\n    at async createTeammatePaneInSwarmView (B:/~BUN/root/claude.exe:2025:16560)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-02-06T12:56:51.560Z"},{"error":"Error: [TmuxBackend] Failed to get pane count for #session_name:#window_index (exit 1): can't find session: #session_name\n    at getCurrentWindowPaneCount (B:/~BUN/root/claude.exe:2026:837)\n    at async createTeammatePaneWithLeader (B:/~BUN/root/claude.exe:2029:496)\n    at async createTeammatePaneInSwarmView (B:/~BUN/root/claude.exe:2025:16560)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-02-06T12:57:00.843Z"},{"error":"Error: Could not determine pane count for current window\n    at createTeammatePaneWithLeader (B:/~BUN/root/claude.exe:2029:523)\n    at async createTeammatePaneInSwarmView (B:/~BUN/root/claude.exe:2025:16560)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-02-06T12:57:00.843Z"},{"error":"Error: EPERM: operation not permitted, symlink 'C:\\Users\\nikiforovall\\.claude\\projects\\C--Users-nikiforovall-dev\\e8a039b3-3286-489a-a517-9b6e8c564da5\\subagents\\agent-a537b02.jsonl' -> 'C:\\Users\\NIKIFO~1\\AppData\\Local\\Temp\\claude\\C--Users-nikiforovall-dev\\tasks\\a537b02.output'\n    at symlinkSync (unknown)\n    at kFH (B:/~BUN/root/claude.exe:1316:1154)\n    at kRD (B:/~BUN/root/claude.exe:1428:1523)\n    at <anonymous> (B:/~BUN/root/claude.exe:2043:972)\n    at <anonymous> (B:/~BUN/root/claude.exe:2043:1893)\n    at run (node:async_hooks:62:22)\n    at sPH (B:/~BUN/root/claude.exe:1173:94)\n    at call (B:/~BUN/root/claude.exe:2043:667)\n    at async cUE (B:/~BUN/root/claude.exe:3465:13995)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-02-06T12:57:07.972Z"},{"error":"Error: EPERM: operation not permitted, symlink 'C:\\Users\\nikiforovall\\.claude\\projects\\C--Users-nikiforovall-dev\\e8a039b3-3286-489a-a517-9b6e8c564da5\\subagents\\agent-ac6fe93.jsonl' -> 'C:\\Users\\NIKIFO~1\\AppData\\Local\\Temp\\claude\\C--Users-nikiforovall-dev\\tasks\\ac6fe93.output'\n    at symlinkSync (unknown)\n    at kFH (B:/~BUN/root/claude.exe:1316:1154)\n    at kRD (B:/~BUN/root/claude.exe:1428:1523)\n    at <anonymous> (B:/~BUN/root/claude.exe:2043:972)\n    at <anonymous> (B:/~BUN/root/claude.exe:2043:1893)\n    at run (node:async_hooks:62:22)\n    at sPH (B:/~BUN/root/claude.exe:1173:94)\n    at call (B:/~BUN/root/claude.exe:2043:667)\n    at async cUE (B:/~BUN/root/claude.exe:3465:13995)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-02-06T12:57:10.760Z"},{"error":"Error: EPERM: operation not permitted, symlink 'C:\\Users\\nikiforovall\\.claude\\projects\\C--Users-nikiforovall-dev\\e8a039b3-3286-489a-a517-9b6e8c564da5\\subagents\\agent-aa3e5dd.jsonl' -> 'C:\\Users\\NIKIFO~1\\AppData\\Local\\Temp\\claude\\C--Users-nikiforovall-dev\\tasks\\aa3e5dd.output'\n    at symlinkSync (unknown)\n    at kFH (B:/~BUN/root/claude.exe:1316:1154)\n    at kRD (B:/~BUN/root/claude.exe:1428:1523)\n    at <anonymous> (B:/~BUN/root/claude.exe:2043:972)\n    at <anonymous> (B:/~BUN/root/claude.exe:2043:1893)\n    at run (node:async_hooks:62:22)\n    at sPH (B:/~BUN/root/claude.exe:1173:94)\n    at call (B:/~BUN/root/claude.exe:2043:667)\n    at async cUE (B:/~BUN/root/claude.exe:3465:13995)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-02-06T12:57:13.700Z"},{"error":"Error: Request was aborted.\n    at XW$ (B:/~BUN/root/claude.exe:838:99554)\n    at lnI (B:/~BUN/root/claude.exe:5693:4372)\n    at nnI (B:/~BUN/root/claude.exe:5698:7410)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-02-06T12:57:32.437Z"},{"error":"Error: Request was aborted.\n    at makeRequest (B:/~BUN/root/claude.exe:333:3940)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-02-06T12:57:32.439Z"},{"error":"Error: Request was aborted.\n    at makeRequest (B:/~BUN/root/claude.exe:333:3940)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-02-06T12:57:32.440Z"},{"error":"Error: […

Note: Content was truncated.

View original on GitHub ↗

14 Comments

NikiforovAll · 6 months ago

<img width="1240" height="153" alt="Image" src="https://github.com/user-attachments/assets/cd2f3b93-1392-42fd-b6b6-a70740d849d0" />

NikiforovAll · 6 months ago

Additional findings from investigation

Tried to work around the #session_name:#window_index issue by creating a tmux wrapper script that resolves format variables before passing to the real binary.

What we tried:

  1. Created a wrapper at ~/bin/tmux that intercepts calls and resolves #session_name / #window_index via tmux display-message -p '#{session_name}'
  2. Verified ~/bin/tmux is found first in PATH (which -a tmux confirmed it)
  3. Added logging to the wrapper

Result: The wrapper was never called — the log file remained empty. Claude Code's bundled binary (claude.exe) appears to resolve tmux via absolute path (/usr/bin/tmux) internally, bypassing shell PATH entirely. This means alias/wrapper approaches cannot fix the issue — it needs to be fixed in Claude Code's tmux backend code.

Environment: Windows 11, MINGW64/Git Bash, tmux 3.6a, Claude Code 2.1.34

michael-dg · 6 months ago

Same problem here with windows 11/wezterm/tmux. Tried to ask claude to fix the issue but here is the answer:

I found the root cause. Look at this output from the compound tmux command:

session=#\{session_name\ window=#\{window_id\ panes=#\{window_panes\}

The #{} tmux format strings are getting escaped by MSYS2's bash in certain invocation contexts. When Claude Code internally runs tmux display-message -p '#{window_panes}' to count panes, the #{} sequences get mangled instead of being interpreted by tmux, so it gets back garbage instead of a number — hence "Could not determine pane count".

This is a Claude Code platform bug on Windows/MSYS2 — the tmux format strings aren't being passed through correctly.

You can't fix it from your side.

NikiforovAll · 6 months ago

Using Claude Code on Windows has been one of the most frustrating experiences lately. Sometimes, new features often don't work from the first try🙈

Takeuch-Code · 6 months ago

Same problem here with Windows 11/WindowsTerminal/tmux.

Case 1: Fails (format string at beginning)

$ tmux.exe display-message -p '#{window_panes}'
#window_panes

Expected: 3
Actual: #window_panes (literal string)

Case 2: Works (format string with prefix)

$ tmux.exe display-message -p 'x #{window_panes}'
x 3

Result: Format string is expanded correctly

Case 3: Works (format string with text prefix)

$ tmux.exe display-message -p 'Panes: #{window_panes}'
Panes: 3

Result: Format string is expanded correctly

Josefvz · 6 months ago

Additional confirmation + diagnostic data

Confirming this on Claude Code 2.1.56 (latest). Tested across two different terminal emulators to rule out the terminal layer:

| Terminal Host | Emulator | tmux | Result |
|---------------|----------|------|--------|
| Windows Terminal | conpty | 3.6a | FAIL — "Could not determine pane count" |
| git-bash.exe | mintty | 3.6a | FAIL — same error |

Window size is irrelevant — tested maximized (209x50), normal (120x29), and fresh restarts. Same failure every time.

Extra diagnostic detail

The #{...} format string escaping issue (identified by @Takeuch-Code) also explains why terminal size detection appears broken in Claude Code's subprocess:

| Method | Result | Notes |
|--------|--------|-------|
| tput cols / tput lines | 80 / 24 (default) | Falls back to default in subprocess |
| stty size | "Inappropriate ioctl for device" | No pty attached to subprocess |
| $COLUMNS / $LINES | empty | Not inherited |
| tmux display-message -p '#{client_width}x#{client_height}' | Correct (209x51) | Only works from bash, not when Claude Code invokes it internally |

So even if Claude Code tried tmux display-message as a fallback, it would still hit the same #{...} escaping issue when invoking via MSYS2 bash.

Additional observation: TMUX socket path

The $TMUX variable on MINGW64 uses a Windows-style drive letter:

TMUX=C:/Users/JosefvanZyl/AppData/Local/Temp/tmux-4096/default,3437,0

vs expected Unix-style /tmp/tmux-1000/default. This may cause secondary parsing issues if the code splits on : or expects / as the first character.

Environment
  • OS: Windows 11 (10.0.26200.7840)
  • Shell: MINGW64_NT-10.0-26200 3.6.5-22c95533.x86_64
  • Claude Code: 2.1.56
  • tmux: 3.6a
  • Node.js: v22.21.1
What works

TeamCreate, TeamDelete, TaskCreate, and Task (without team_name) all succeed. Only teammate spawn with team_name fails.

psmux · 5 months ago

This MSYS2 #{...} escaping issue is fundamentally unfixable in GitBash because the shell layer will always mangle tmux format strings. An alternative: psmux — a native Windows tmux implementation that eliminates the MSYS2 layer entirely.

psmux maintainer here. The root cause here is well-identified: MSYS2's bash mangles #{session_name}, #{window_panes}, etc. when Claude Code invokes tmux internally. As @Takeuch-Code demonstrated:

# MSYS2/GitBash — FAILS
$ tmux.exe display-message -p '#{window_panes}'
#window_panes   # literal string, not resolved

# psmux on native Windows — WORKS
$ tmux display-message -p '#{window_panes}'
3               # correctly resolved

Why psmux avoids this

psmux is a native Windows binary (~4.5MB, Rust, ConPTY) — no MSYS2, no MinGW, no bash translation layer. When Claude Code calls tmux display-message -p '#{window_panes}', the format strings go directly to the psmux process without any shell escaping in between.

It also fixes @Josefvz's socket path issue. psmux sets:

TMUX=/tmp/psmux-1000/default,<pid>,0

This matches the Unix-style format that Claude Code's parser expects (splits on :, expects / prefix) — unlike the C:/Users/.../tmux-4096/default path from MSYS2 tmux.

How to try it

winget install psmux

Then run Claude Code from PowerShell or Windows Terminal (not GitBash). psmux ships as tmux.exe, so Claude Code's tmux detection (which tmux, $TMUX env var) works automatically.

76 tmux-compatible commands, including all the ones Claude Code's TmuxBackend uses: display-message, split-window, list-panes, send-keys, select-pane, resize-pane.

Current release: v0.4.10 — MIT licensed.

The tmux -V command also works correctly (fixed in #42), which is how many tools detect tmux presence.

NikiforovAll · 5 months ago

@marlocarlo create project, thank you for sharing. If we talk about feature partiy. Will plugin system/customizations work for psmux? I use alacritty and gitbash

psmux · 5 months ago

Yes, technically, it should. I've not tested it with git bash ,only tried Powershell psmux plugins on psmux but I think it should work, perhaps tmux plugins as Psmux is compatible. Let me know if you face issues. I'll try to address it

Psmux can be made to load git bash as the shell when you run Psmux from powershell. I fixed some issues related to this in the latest commits and tested.That works. The plugin part inside gitbash,I am not sure.

Josefvz · 5 months ago

@marlocarlo First off, thanks for the feedback!
I installed psmux and gave it a go. Two issues so far (though it's completely possible I'm doing something wrong.)

I have to launch tmux (in Windows Terminal) before Claude, otherwise it doesn't pick tmux up at all.
Claude does create additional instances (panes)! So progress!! However, it looks like the command being passed to the spawned tmux instances is broken; see the image below.

Let me know if I need to change something, or whether we should move this discussion to another issue (I'm not sure whether this is a psmux or Claude issue).
<img width="1909" height="1023" alt="Image" src="https://github.com/user-attachments/assets/8a90df9b-44aa-4412-a62a-59ba8818e8e0" />

psmux · 5 months ago

@Josefvz Great catch — thank you for the detailed report and screenshot!

I've identified and fixed both issues. The commit is here: https://github.com/marlocarlo/psmux/commit/fde3adf

What was broken

1. The -c (start directory) flag was silently ignored

When Claude Code runs split-window -h -d -c <dir> -P -F "#{pane_id}", the -c argument was being parsed correctly but the value was discarded (_start_dir) before reaching the pane creation code. This means teammate panes always spawned in psmux's own working directory instead of the project directory Claude intended.

Fixed: start_dir is now wired through the full call chain — app.rs, server/mod.rs, commands.rs, input.rs — so both split-window -c and new-window -c correctly set the working directory of new panes.

2. build_command() sent /C to bash instead of -c

When psmux spawns a command in a pane, it needs to invoke the shell with the right flag. The code only detected PowerShell (-Command) and defaulted everything else to cmd.exe /C. So if your default shell is bash, the command bash /C "echo hello" would be sent — which bash doesn't understand.

Fixed: build_command() now does proper file-stem detection:

  • pwsh / powershell-Command
  • bash / sh / zsh / fish / dash / ash-c
  • fallback → /C (cmd.exe)

How to update

cargo install --git https://github.com/marlocarlo/psmux.git

Or if you have the repo cloned:

git pull && cargo install --path .

Verified with tests

I've added a comprehensive test suite (tests/test_claude_compat_fixes.ps1) that covers the full Claude Code teammate workflow — 26 tests all passing:

  • split-window -c and new-window -c correctly set CWD
  • split-window -h -d -c <dir> -P -F "#{pane_id}" (exact Claude Code spawn pattern)
  • Bash shell command dispatch using -c instead of /C
  • send-keys to split panes
  • Full end-to-end teammate spawn simulation

Let me know if this resolves it for you!

Josefvz · 5 months ago

@NikiforovAll I can confirm that this now works on my side @psmux and the team that side has done some great work on psmux!

<img width="1898" height="1023" alt="Image" src="https://github.com/user-attachments/assets/9ef0264d-c040-4448-8677-49191977797a" />

Hopefully this solves your issue as well

github-actions[bot] · 4 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

github-actions[bot] · 4 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.