Agent teams: tmux socket unlinked while server alive — ghost servers and leaked tmux-spawn scopes
Summary
Agent teams tmux management unlinks the socket file at /tmp/tmux-<uid>/default while the tmux server process is still running. This creates unreachable "ghost" tmux servers and leaks tmux-spawn-*.scope systemd transient units. The user's interactive tmux is also broken because agent teams share the default socket.
Environment
- Claude Code: Opus 4.6 via CLI
- OS: Linux 6.17.0-1011-azure (Ubuntu)
- tmux: default system package
- Platform: Linux headless server (SSH)
Symptoms
$ tmux ls
error connecting to /tmp/tmux-1000/default (No such file or directory)
This is not the normal "no server running" message — it means the socket file was deleted while tmux still expected to find one.
Investigation findings
Two ghost tmux servers running unreachable
Both were tmux new-session -d -s squad-goals processes, still alive but unreachable via any tmux client:
| PID | Started (UTC) | Uptime at discovery | RSS |
|---|---|---|---|
| 17000 | 2026-04-28 06:21 | 1d 7h 54m | 14.8 MB |
| 1115212 | 2026-04-28 23:26 | 14h 49m | 21.1 MB |
lsof showed both bound to /tmp/tmux-1000/default with different socket inodes (70641 and 4242690). The path had been unlinked from the filesystem — both servers were listening into the void.
80 leaked tmux-spawn-* systemd scopes
The user's systemd manager had 80 tmux-spawn-*.scope transient units in active (running) state, all parented to the two ghost server PIDs.
- 77 of 80 scopes had zero processes inside — their pane processes had exited but the transient scopes don't self-deactivate when empty
- 3 scopes still contained idle
-bashshells detached from any client
These consumed 80 systemd unit slots, 80 cgroup directories, and associated file descriptors — all leaked.
Likely sequence
- Agent team spawns tmux server A, binds socket at
/tmp/tmux-1000/default - Team teardown (or a new team spawn) unlinks the socket file while server A is still running
- Next agent team spawn can't find a server (no socket), starts server B, creates a new socket
- That socket is also unlinked during teardown
- Both servers are now ghosts — alive but unreachable
- The user's interactive
tmux lssees neither server
User's interactive tmux is collateral damage
Agent teams use the shared default tmux socket (/tmp/tmux-1000/default). Any socket disruption during team lifecycle breaks the user's interactive tmux sessions too. This is a significant footgun — team operations should not affect user tmux state.
Root cause
Something in the agent teams tmux teardown path removes the socket file at /tmp/tmux-1000/default rather than using tmux kill-session or tmux kill-server. Removing the socket file does not kill the server — it just hides it from all clients, creating a ghost.
Additionally, tmux-spawn-*.scope transient units are never explicitly stopped during teardown. Since systemd transient scopes don't auto-deactivate when their last process exits, they accumulate indefinitely.
Suggested fixes
- Never
rm/unlinkfiles under/tmp/tmux-*/— the tmux server owns its socket file lifecycle. Usetmux kill-session -t <name>ortmux kill-serverfor teardown.
- Isolate team sockets from user sessions — use
tmux -L <team-id>(named socket) instead of the default socket. This way team lifecycle cannot break the user's interactive tmux.
- Reap
tmux-spawn-*scopes on teardown — after killing a team session, explicitlysystemctl --user stopanytmux-spawn-*.scopeunits that belonged to that team's server PID.
- Postcondition check — after team teardown, verify that no tmux processes from the team are still alive and no orphaned scopes remain.
Related
- #41877 — similar ghost-server outcome but different trigger (cgroup race crash vs. socket unlink)
Cleanup that was required
kill 17000 1115212 # SIGTERM both ghost servers
systemctl --user stop tmux-spawn-*.scope # reap 77 empty scopes
rm /tmp/tmux-1000/default # remove orphaned socket
After cleanup: 0 ghost processes, 0 leaked scopes, tmux ls returns normal "no server running" message.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗