-
-
Notifications
You must be signed in to change notification settings - Fork 80.7k
claude-cli auth failure shows generic error instead of re-auth hint when OAuth token is expired #97553
Copy link
Copy link
Closed
Labels
P2Normal backlog priority with limited blast radius.Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.ClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.ClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.ClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.Auth, provider routing, model choice, or SecretRef resolution may break.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.Very strong issue quality with high-confidence source-level or clear reproduction.maturity:stableIssue affects a taxonomy feature currently scored M4/M5.Issue affects a taxonomy feature currently scored M4/M5.no-staleExclude from stale automationExclude from stale automation
Description
Metadata
Metadata
Assignees
Labels
P2Normal backlog priority with limited blast radius.Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.ClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.ClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.ClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.Auth, provider routing, model choice, or SecretRef resolution may break.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.Very strong issue quality with high-confidence source-level or clear reproduction.maturity:stableIssue affects a taxonomy feature currently scored M4/M5.Issue affects a taxonomy feature currently scored M4/M5.no-staleExclude from stale automationExclude from stale automation
Type
Fields
Priority
None yet
Summary
When
claude-cli/claude-sonnet-4-6(or anyclaude-cli/*model) is used as the active model and the Claude CLI's stored OAuth token has expired, the user receives the generic error:instead of the specific re-auth hint that already exists in the codebase:
Root Cause
There are two gaps in the error-handling chain.
Gap 1 —
classifyOAuthRefreshFailuredoesn't recognise the Claude CLI's 401 messageoauth-refresh-failure-W3UM3WkM.js→isOAuthRefreshFailureMessageonly matches messages generated by openclaw's own OAuth-refresh machinery:When the
claudesubprocess has an expired token it emits its own message:None of the three strings match →
classifyOAuthRefreshFailurereturnsnull→ the re-auth hint inreply-usage-state-q7j5CVEd.js:1107-1115is never reached.Gap 2 —
isAuthErrorMessagecatches it but isn't wired into the channel reply pathA separate
isAuthErrorMessage()function insanitize-user-facing-text-DLYR-7y_.jshas patterns that would match the Claude CLI's output ("authentication",/\b401\b/,"expired"). However, it is only used for failover classification (errors-BmvajW3H.js:654) and TUI display (tui-D1r4yDv-.js:2741) — not insidebuildExternalRunFailureReply, so the auth signal never reaches the Telegram/channel reply.Why this matters structurally
cli-shared-BcJqwrq-.jsdefinesCLAUDE_CLI_CLEAR_ENV, which deliberately stripsANTHROPIC_API_KEY(and all related env vars) before spawning theclaudesubprocess. This means openclaw statically knows the subprocess can only authenticate via its stored OAuth token. A 401 exit from the subprocess is therefore unambiguously an OAuth expiry — but this knowledge is never used to promote the error to anOAuthRefreshFailureError.Reproduction
claude-cli/claude-sonnet-4-6as the active model.~/.claude/.credentials.json→claudeAiOauth.expiresAt).Expected Behaviour
Suggested Fix
Two changes:
1. Extend
isOAuthRefreshFailureMessage(or add aisClaudeCliAuthFailuresibling) to recognise the Claude CLI's 401 output:2. In
attempt-execution-B_ltmss6.js, sinceCLAUDE_CLI_CLEAR_ENVguarantees the subprocess uses OAuth, promote a subprocess 401 exit directly to anOAuthRefreshFailureError— so the right hint is shown regardless of whatever exact wording the CLI happens to emit in future versions.Environment