fix(agents): clear stale CLI session on any FailoverError, not only session_expired#77141
fix(agents): clear stale CLI session on any FailoverError, not only session_expired#77141hclsys wants to merge 3 commits into
Conversation
…ession_expired Previously the stale-binding recovery branch in runPreparedCliAgent only triggered when err.reason === "session_expired". Failures with reason "timeout" or "unknown" would rethrow immediately, leaving the dead session binding in place and cascading every subsequent turn to API fallbacks. Widen the condition to retry fresh for any FailoverError from an active reused CLI session. Add regression tests for both timeout and unknown failure reasons. Fixes openclaw#77089. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
|
Codex review: needs changes before merge. Summary Reproducibility: yes. Source inspection on current main shows timeout and unknown CLI FailoverError paths bypass the session_expired-only stale-binding clear; the PR’s remaining blocker can be reproduced by a stale-session timeout followed by a fresh retry that fails with a different FailoverError reason. Next step before merge Security Review findings
Review detailsBest possible solution: Move the persisted binding clear into the store-aware path before starting the fresh retry, then retry once and persist any replacement binding while preserving existing fallback behavior. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection on current main shows timeout and unknown CLI FailoverError paths bypass the session_expired-only stale-binding clear; the PR’s remaining blocker can be reproduced by a stale-session timeout followed by a fresh retry that fails with a different FailoverError reason. Is this the best way to solve the issue? No, not as-is. Widening recovery is the right direction, but the stored binding must be cleared based on the original reused-session failure before the fresh retry can fail with another reason. Full review comments:
Overall correctness: patch is incorrect Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 89a15fddaf84. |
Log last-8 chars of session ID instead of raw value to avoid exposing host-local resume identifiers in support bundles. Also fix changelog PR reference (openclaw#77140 → openclaw#77141). Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This comment was marked as low quality.
This comment was marked as low quality.
…ailoverErrors The cli-runner already retried fresh for any FailoverError, but the store-clear in attempt-execution only fired for session_expired. Timeout and unknown failures left the stale binding in the store, causing the next turn to fail again. Also adds regression tests for timeout and unknown failure reasons at the attempt-execution caller level. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Problem
The stale-session recovery path in
runPreparedCliAgentonly cleared thebinding and retried fresh when
err.reason === "session_expired". Failureswith reason
"timeout"(watchdog kill) or"unknown"(generic CLI crash)would rethrow immediately, leaving the dead session binding in place. Every
subsequent turn then tried to resume the same dead session, failed in
milliseconds, and cascaded to API fallback (Opus → Sonnet).
The incident in #77089 shows a gateway that degraded for 4+ hours because a
single
timeoutfailure left a stale binding that nothing cleared until agateway restart.
Fix
Remove the
err.reason === "session_expired"narrowing. AnyFailoverErrorfrom an active reused CLI session now clears the binding and retries once
fresh. If the fresh retry also fails, it falls through to the API fallback
chain as before. Add a
cliBackendLog.warnso operators can see when anon-
session_expiredreason triggered the recovery.Changes
src/agents/cli-runner.ts— removereason === "session_expired"guard,add warn log, import
cliBackendLogsrc/agents/cli-runner.reliability.test.ts— two new regression tests:FailoverError reason timeout→ retry succeeds with fresh sessionFailoverError reason unknown→ retry succeeds with fresh sessionTests
38/38 reliability tests pass.
pnpm oxlintclean.pnpm tsc --noEmitclean.Fixes #77089.
Co-Authored-By: Claude Sonnet 4.6 [email protected]