[BUG] --resume while the original process is still alive → two live processes of one session act on the repo concurrently (orphaned twin keeps working headless)
Disclosure: this report was investigated and written by Claude Code itself (the affected, resumed session), together with the user, who reviewed and filed it from his account. Happy to provide sanitized transcript excerpts on request.
Preflight
- [x] Searched existing issues — closest match is #26123 (closed,
/resumehistory inaccessible), which is a different bug. - [x] Single bug report.
- [x] Latest extension version at time of occurrence (VS Code extension 2.1.201;
claude --versionCLI reports 2.1.195).
What's Wrong?
Resuming a session (--resume <session-id>) while the original process for that same session is still alive results in two live processes of one session, both acting on the same workspace independently.
Observed sequence (macOS, VS Code native extension):
- A long-running session (a code-review agent) had armed a persistent background
Monitor(a git-HEAD commit watcher) and was running with permission modeauto. - The VS Code extension restarted its tabs. The tab came back as a new process launched with
--resume <same-session-id>. - The original process never exited. It survived headless under the same extension host — full context still in memory, its persistent Monitor still armed.
- From then on, both processes acted on the repo concurrently:
- The orphaned twin woke on every git commit (via its Monitor), wrote review blocks, committed, and pushed — with no visible tab anywhere.
- The resumed process (the visible tab) collided with it (
File has been modified since readon files the twin edited seconds earlier).
- Diagnosis was exceptionally hard because both processes append to the same transcript jsonl (same session id → same file). The resumed process saw the twin's tool calls interleaved into "its own" history and concluded it had done the work itself and forgotten (post-compaction amnesia). All transcript-based forensics self-attributed.
- The user finally identified the twin by committing a bait file asking "reviewer, who are you?" — the orphan's watcher fired, and it replied in a commit, self-identifying with the same session ID as the visible tab.
ps at the time (paths shortened; note the original with no --resume from a day earlier, plus the resumed twin):
PID 11462 started Jul 7 20:26 .../native-binary/claude --output-format stream-json ... (no --resume; ORIGINAL, orphaned)
PID 41523 started Jul 8 20:10 .../native-binary/claude ... --resume f075f82b-... (RESUMED, visible tab)
Both wrote to ~/.claude/projects/<project>/f075f82b-....jsonl.
Impact: autonomous duplicate work (duplicate commits/pushes to a shared repo), file-edit collisions, and near-impossible attribution. With permission-mode auto + a persistent Monitor, the orphan is effectively a self-driving headless agent the user cannot see or stop from any UI (they had "3 tabs open" and a 4th actor committing).
What Should Happen?
A session ID should map to at most one live process:
- On
--resume, detect that a live process already owns the session (pidfile/lock per session id) and either (a) signal the original to exit before resuming, or (b) refuse/warn: "session <id> is already running (pid N)". - On extension restart/deactivate, terminate child
claudeprocesses rather than orphaning them. - Two processes must never interleave writes into one transcript jsonl.
- Nice-to-have: a way to see running headless sessions (e.g.
claude ps) so an orphan is discoverable withoutps auxforensics.
Error Messages/Logs
# Collision symptom in the resumed session while the twin edited the same file:
Edit failed: "File has been modified since read, either by the user or by a linter.
Read it again before attempting to write it."
# The orphan's self-identification (it committed this reply when baited):
"I am the REVIEWER session (id f075f82b-...); stopped my commit-watcher (bfbv51os6) so I stand down.
To fully close: ... kill the reviewer PID."
Steps to Reproduce
- In the VS Code extension (or any setup where the
claudeprocess can outlive its client), start a session and give it a persistent background Monitor (e.g. awhile true; do git rev-parse HEAD; sleep 20; donecommit watcher) with permission mode allowing autonomous tool use. - Cause the client to restart without the underlying
claudeprocess exiting (in our case: extension restart; the old native-binary processes survived under the same extension-host parent — reproducible by killing/reloading the extension host UI while children persist). - Reopen the same conversation → a new process starts with
--resume <session-id>. ps aux | grep native-binary/claude→ both processes are alive; the old one has no--resumeflag.- Trigger the orphan's Monitor (make a git commit).
- Observe the orphan wake and act (edit/commit) concurrently with the resumed process; observe both appending to the same
~/.claude/projects/<project>/<session-id>.jsonl.
Environment
- Claude Code Version: VS Code extension 2.1.201 (native binary);
claude --versionCLI = 2.1.195 - Model: Opus (4.8)
- Regression?: I don't know
- Platform: Anthropic API
- OS: macOS (Darwin 25.4.0, arm64)
- Terminal: VS Code native extension (closest dropdown: VS Code integrated terminal)
Additional Information
- The orphan behaved "correctly" per its instructions the whole time — the bug is purely process lifecycle: resume-without-exclusivity + orphaned children + shared transcript file.
- Workaround that ended it: committing a bait file (the orphan's watcher fired, it self-identified and stood down), then killing the stale PID / fully quitting VS Code.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗