Summary
The bundled claude-cli backend keeps a Claude stdio process alive per OpenClaw session and reuses it across turns via stored session id. After an AbortError or FailoverError on a turn, OpenClaw retains the stored session id and reuses the same (likely damaged) binary on the next turn. The reused binary frequently accepts the new prompt over stdin but produces no output, hitting the 60s no-output watchdog and surfacing a generic error to the user. The damaged session persists until a manual /reset, daily reset, idle expiry, or transcript deletion cuts it.
Reproduction (observed)
- Turn N hits
AbortError (e.g., user interrupt during a slow tool call) or FailoverError.
- Stored CLI session id is not invalidated.
- Turn N+1 (any time later, even hours) reuses the stored id →
claude live session reuse.
- Binary accepts the prompt over stdin but never emits output.
- After 60s of silence, watchdog kills the subprocess with
reason=abort, model fallback shows next=none detail=CLI produced no output for 60s and was terminated.
- User sees:
⚠️ Something went wrong while processing your request. Please try again, or use /new to start a fresh session.
Concrete log evidence (one occurrence)
22:37:54 [agent/cli-backend] cli exec: provider=claude-cli model=opus
useResume=true reuse=reusable resumeSession=<redacted-session-id>
22:37:54 [agent/cli-backend] claude live session reuse: provider=claude-cli model=claude-opus-4-6
[146 seconds of complete silence — no chunks, no tools, no output]
22:40:21 [agent/cli-backend] claude live session close: reason=abort
22:40:21 [model-fallback/decision] reason=timeout next=none
detail=CLI produced no output for 60s and was terminated
Earlier the same day, the same backend hit AbortError. The session id reused at 22:37 was likely the damaged one from that earlier abort.
Existing protections (not sufficient)
- Phantom-binding check verifies transcript existence before reuse — only catches deleted sessions, not wedged ones.
session.reset.idleMinutes cuts the underlying CLI session on idle — preventative but coarse; doesn't react to the actual error signal.
Proposed fix
On any AbortError / FailoverError from a claude-cli backend turn, invalidate the stored resumeSession id for that backend. Next turn spawns a fresh claude binary instead of reusing the damaged one.
Optional refinement: only invalidate when the abort/error happened with useResume=true reuse=reusable (i.e., reusing an existing live session), since fresh-spawn aborts don't taint the next turn.
Workaround today
/reset soft drops the stored CLI session id without clearing the transcript.
Summary
The bundled
claude-clibackend keeps a Claude stdio process alive per OpenClaw session and reuses it across turns via stored session id. After anAbortErrororFailoverErroron a turn, OpenClaw retains the stored session id and reuses the same (likely damaged) binary on the next turn. The reused binary frequently accepts the new prompt over stdin but produces no output, hitting the 60s no-output watchdog and surfacing a generic error to the user. The damaged session persists until a manual/reset, daily reset, idle expiry, or transcript deletion cuts it.Reproduction (observed)
AbortError(e.g., user interrupt during a slow tool call) orFailoverError.claude live session reuse.reason=abort, model fallback showsnext=none detail=CLI produced no output for 60s and was terminated.⚠️ Something went wrong while processing your request. Please try again, or use /new to start a fresh session.Concrete log evidence (one occurrence)
Earlier the same day, the same backend hit
AbortError. The session id reused at 22:37 was likely the damaged one from that earlier abort.Existing protections (not sufficient)
session.reset.idleMinutescuts the underlying CLI session on idle — preventative but coarse; doesn't react to the actual error signal.Proposed fix
On any
AbortError/FailoverErrorfrom aclaude-clibackend turn, invalidate the storedresumeSessionid for that backend. Next turn spawns a freshclaudebinary instead of reusing the damaged one.Optional refinement: only invalidate when the abort/error happened with
useResume=true reuse=reusable(i.e., reusing an existing live session), since fresh-spawn aborts don't taint the next turn.Workaround today
/reset softdrops the stored CLI session id without clearing the transcript.