Attaching to a stopped/idle background agent crashes the worker with contradictory "currently running as a background agent" error
Summary
Attaching to a stopped/idle background agent session from the claude agents (agent view / FleetView) list crashes the worker with a self-contradictory error: the stopped session reports that it is "currently running as a background agent." Sessions with a running icon attach fine; every session with a stopped/idle icon fails the same way.
Environment
- Claude Code version:
2.1.199 - OS: macOS (Darwin 25.5.0)
- Install: native (
~/.local/share/claude/versions/2.1.199)
Steps to reproduce
- Open the agent list with
claude agents. - Select a session showing the running icon (animated star) and press Enter — attaches fine.
- Select any session showing the stopped/idle icon and press Enter to attach.
Actual behavior
Attaching to the stopped/idle session fails with:
Session <session-id> is currently running as a background agent (bg). Use `claude agents` to find and attach to it, or add --fork-session to branch off a copy.
[worker crashed (exit 1 — exit_with_message) — respawning…]
This is contradictory — the session is displayed as stopped/idle, yet the message claims it is "currently running as a background agent." It reproduces for every stopped/idle session, consistently. Running sessions (star icon) are unaffected.
The same message appears when trying claude --resume <session-id> on such a session.
Expected behavior
Pressing Enter on a stopped/idle background session should wake/restart its process and attach, rather than emitting a "currently running" error and crashing the worker.
Workaround
claude --resume <session-id> --fork-session successfully branches a copy and opens it. However, if that forked session is then stopped (Ctrl+X), re-attaching to it fails again with the same error under a new session ID — so each stop produces another session that cannot be re-attached from the list.
Showing cached comments. Read the full discussion on GitHub ↗
7 Comments
Additional triage signal: this started appearing right after upgrading to
2.1.199(installed the same day). Prior versions on this machine were2.1.198(day before) and2.1.197.At the same time, this version also began emitting startup warnings for malformed permission
denyrules (rules written asRead ~/.netrcinstead ofRead(~/.netrc)) that had been silently inert in earlier versions — i.e.2.1.199clearly added/changed some startup validation and error surfacing. That makes me suspect the stopped-session attach failure may have been occurring silently before as well, and a recent change just started surfacing it as a hard worker crash. Flagging in case the regression window is the2.1.197→2.1.199range.I experience a similar issue; I'm on the latest Claude Code. Just reported via
/feedback.UPD: Downgrading to
2.1.197fixed the issue for me; I haven't tried2.1.198, though.Hit the same crash-loop on
2.1.201(macOS, native install) and did some binary/state spelunking that may help pinpoint the root cause. Everything below reproduced today with ~140 completed bg jobs on disk.Symptom recap
Attaching (or
--resume) to any settled (done/stopped/failed) background session fails; live workers attach fine. The daemon log shows the loop — every revival attempt settlescrashed~22s after spawn:The worker's stderr is the resume guard message itself, so the "contradictory" error in the OP is the revived worker refusing to resume its own session.
What the guard does (from the 2.1.201 bundle)
The resume path runs a
resume_live_check:Ffelists live sessions from the per-PID registry (~/.claude/sessions/*.json), keeping entries whose PID is alive (and proc start time matches), and returns a hit whensessionIdmatches withkind !== "interactive":There is no self-exclusion (own PID / own
CLAUDE_CODE_SESSION_ID). The revived worker registers itself in~/.claude/sessions/<pid>.jsonwithkind: "bg"and the target sessionId during startup, then the resume path runs the check, finds its own registration, prints the guard error and exits 1 → daemon respawns → loop. Verified the registry entry exists for live workers (kind: "bg",sessionId= the resumed session) and that no stale entry exists for the crashing sessions between attempts — the only candidate the guard can be seeing is the worker itself.Consistent with that mechanism:
--resume) spawn fine — the guard never runs.state.json(templateclaude→bg, dropped--agent, bumpedcliVersion) and it crashed identically.Workarounds that work today
~/.claude/jobs/<short-id>/— the session stops being claimed as bg and plainclaude --resume <id>works again (at the cost of losing the fleet entry).2.1.197datapoint above matches the regression window from the OP's triage (2.1.198/2.1.199).Happy to provide the full daemon.log or run instrumented builds if useful.
Reproducing this on 2.1.201 (macOS arm64, on-demand
origin=transientdaemon). Adding a code-level root cause and a second, independent defect that also produces this refusal, in case it helps the fix.Root cause: agents-view attach is dispatched as a plain
--resume, so it runs the resume-time liveness guard against the very session being attachedWhen attaching from the agents view, the daemon spawns the worker as a plain resume —
claude --resume /…/projects/…/<sessionId>.jsonl --agent claude(confirmed against the live crash-looping process). That resume path runs a liveness guard before attaching (minifiedFfein the 2.1.201 bundle):Ffe→listAllLiveSessions(Bze) reports a session live purely from~/.claude/sessions/<pid>.jsonbeing present with pid alive + matching start-time. So attaching to a bg session — which is legitimately live as a bg agent, or whose host<pid>.jsonis still present mid-handoff — makes the guard fire against the very session being attached, refuse, and exit with causeexit_with_message. The daemon reads that exit as a crash and respawns another plain--resumeworker → same guard → loop.The correct path already exists but isn't taken here:
CLAUDE_BRIDGE_REATTACH_SESSION(bridge-reattach) connects to the running host and bypassesFfe. The defect is that agents-view attach is dispatched as a plain--resumeinstead of a bridge-reattach.This lines up with the self-lock #74198 described before it was closed as a dup of this issue: the dispatched resume worker's guard finds its own job record.
Secondary, independent defect: the PID-reuse check fails open
listAllLiveSessions(Bze) cleans a record only when its pid is dead, and the pid-reuse guard (AO) is lenient:So a reused pid or a flaky/slow
psyields a false "live" → false refusal, independent of any handoff race. Under load this alone crash-loops attach.Suggested fixes
CLAUDE_BRIDGE_REATTACH_SESSION), not a plain--resume, so it never routes through the resume-timeFfeguard.AOfail closed: onpserror/timeout or missingprocStart, treat the record as not matching (i.e. not live) rather than assuming same-process.<pid>.jsonwhen the pid is reused (alive but different process / procStart mismatch), not only when dead.exit_with_messagethe daemon reads as a crash.Workarounds (consistent with the OP's)
claude --resume <id> --fork-sessionbypasses the guard.rm ~/.claude/sessions/*.json,rm -rf /tmp/cc-daemon-*, relaunch.Reproduced on Linux (Ubuntu, kernel 6.8), Claude Code 2.1.201, native install.
Same contradictory refusal on attach, but I want to flag an aggravating behavior that may deserve its own fix: the daemon's pty-host supervisor treats the
exit_with_messageexit as a worker crash and respawns it indefinitely. Each respawned worker hits the same "Session <id> is currently running as a background agent" refusal, exits 1, and gets respawned again:This loops forever inside the pty-host, so the attach viewer terminal becomes impossible to exit cleanly — the only way out is killing the pty-host/viewer processes from another terminal. The respawn also leaves focus-reporting escapes enabled, so the terminal prints literal
^[[Iafterwards (same symptom as #74508).Suggested fix independent of the state-contradiction root cause:
exit_with_messageis a deliberate, user-facing refusal — the supervisor should treat it as terminal and not respawn, or at minimum cap retries with backoff.I reproduced this using
claudeversion2.1.201onUbuntu 24.04.4 LTS(installed via mise, although I doubt that matters).Notably, it _does_ seem to eventually respawn the worker/resume the agent, but it takes a few seconds for it to retry.
I tried downgrading to determine when this regression was introduced. It seems to work as expected on
2.1.198, but not2.1.199. I'll be sticking with2.1.198until I hear this has been addressed.Hit the same failure with one detail worth capturing here: it isn't always a single crash — it can become an indefinite crash-loop. Attempting to resume/attach produces a repeating
that never resolves into an attach, alongside the contradictory:
There's no path forward from the attach attempt itself — the only escape is to stop the session from the separate
claude agentslist view. Same-spirit fix as this issue: attaching to a session in this state should either succeed, or fail once with a clear, actionable error — never looprespawning…indefinitely._(Originally filed as a combined report in #74249; splitting the detail here since this is the canonical attach-crash issue.)_