fix(claude-local): classify an unrefreshable OAuth session as auth required - #11073
Open
juancarlosrial76-code wants to merge 1 commit into
Open
Conversation
|
✅ All checks passing — ready for Greptile review and maintainer approval. — commitperclip |
Contributor
Greptile SummaryThis PR narrowly extends the Claude Local authentication classifier to recognize an expired OAuth session that cannot be refreshed.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| packages/adapters/claude-local/src/server/parse.ts | Extends the existing authentication-required regex with the Claude CLI’s unrefreshable OAuth-session failure sentence. |
| packages/adapters/claude-local/src/server/parse.test.ts | Adds coverage for the new OAuth failure classification and a nonmatching outage-report case. |
Reviews (2): Last reviewed commit: "fix(claude-local): classify an unrefresh..." | Re-trigger Greptile
…quired
The Claude CLI reports a dead OAuth session as
Failed to authenticate: OAuth session expired and could not be refreshed
which matches none of the branches in `CLAUDE_AUTH_REQUIRED_RE` — not
`unauthorized`, not `authentication required` (the CLI says "Failed to
authenticate"), and it is an OAuth session rather than an API key. With
`detectClaudeLoginRequired` returning false and neither the transient-upstream
nor the provider-quota pattern matching either, the run ends up unclassified
and fails hard instead of surfacing `claude_auth_required` and its login path.
On one host's run-log corpus this was the single largest error bucket: 2811 of
8179 failed runs, spread over every one of the 11 agents in a continuous ~79h
window — a shared host credential expiring, not a per-agent problem. Because
nothing classified it, all 11 agents kept being woken and kept burning runs for
the entire window.
Match the CLI's whole failure sentence rather than `OAuth session expired`
alone. `detectClaudeLoginRequired` reads the run's own `result` text, and agents
that *report on* an outage quote that phrase back; counter-checking both forms
over the same corpus, the short form newly matched 5 successful runs while the
anchored form matched none.
juancarlosrial76-code
force-pushed
the
classify-oauth-session-expired
branch
from
August 8, 2026 00:58
58b3079 to
874a7a1
Compare
14 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Thinking Path
Linked Issues or Issue Description
No existing GitHub issue found — describing the bug in-PR.
What happened: every run on a host failed with
Failed to authenticate: OAuth session expired and could not be refreshed, and each one wasrecorded as an unclassified hard failure rather than
claude_auth_required.Expected: an expired/unrefreshable OAuth session is an auth problem, so
detectClaudeLoginRequiredshould reportrequiresLogin: trueand the run should resolve toclaude_auth_required.Why the current code misses it —
CLAUDE_AUTH_REQUIRED_REinpackages/adapters/claude-local/src/server/parse.tshas no branch that this text can hit:unauthorized— not present in the textauthentication\s+required— the CLI says "Failed to authenticate", not "required"invalid\s+api\s+key…— this is an OAuth session, not an API keyWith
requiresLoginfalse and neitherCLAUDE_TRANSIENT_UPSTREAM_REnorCLAUDE_PROVIDER_QUOTA_REmatching, nothing classifies the run.Impact, measured over one host's run logs (12,098 run logs → 11,046
resultevents →8,179 failures). This bucket is larger than every quota wording combined:
resulttextFailed to authenticate: OAuth session expired and could not be refreshedYou've hit your weekly limit · resets …Prompt is too longThe 2811 cases fall on all 11 agents of that host inside one continuous ~79h window, with
failures in 82 distinct hours — one shared host credential expiring, not one agent with a stale
login. Because nothing classified it, all 11 agents kept being woken and kept burning runs for
the entire window.
Dedup search: searched the open PR list for
claude_auth_required/ auth-classificationwork and checked each candidate's current diff (not just its title) for this wording —
#10592, #8028, #5673, #9933 and #11053. None of them touches
OAuth session expired; thephrase appears nowhere in
mastertoday. Refs #10592, Refs #8028, Refs #5673 — those three fixa different, adjacent bug (see Risks).
What Changed
parse.ts: added one branch toCLAUDE_AUTH_REQUIRED_REmatching the CLI's whole failuresentence,
failed to authenticate … oauth session expired and could not be refreshed, with acomment explaining why it is anchored rather than matching the short phrase.
parse.test.ts: two tests pinning both directions — the CLI's failure sentence classifies asauth-required, and a run that merely reports on an OAuth outage does not.
Verification
"classifies an unrefreshable OAuth session" test fail (1 failed | 40 passed), so the test is
not vacuously green.
detectClaudeLoginRequireddoes (per line of the run'sresulttext). The function reads therun's own result text, and agents that report on an outage quote the CLI error back, so the
short form would misread those successful reports as auth failures:
+ oauth\s+session\s+expired+ failed\s+to\s+authenticate…oauth\s+session\s+expiredThe anchored form catches every real case and adds no new false positive.
Risks
Low risk. The change is additive — one alternation branch inside an existing regex — so no
previously-matching input stops matching, and the new branch is narrow enough that it did not
newly match any of the 2,870 successful runs in the corpus.
One adjacent issue this PR deliberately does not touch: in
execute.ts,loginMeta.requiresLoginis the only branch ofresolvedErrorCodenot gated onfailed, so asuccessful run whose text matches this regex is still labelled
claude_auth_required. That ispre-existing and already addressed by #10592, #8028 and #5673, so fixing it here would duplicate
their work and make this PR two concerns. The anchored wording was chosen specifically so this
change adds nothing to that exposure (0 newly-matched successful runs above).
Model Used
Claude Opus 5 (
claude-opus-5[1m]), 1M context window, extended thinking, with tool use andcode execution (measurement scripts run locally over the run-log corpus).
Checklist
Fixes: #/Closes #/Refs #OR (b) described the issue in-PR following the relevant issue template#NNN/github.com/paperclipai/paperclipURLs)docs/...,fix/...) and contains no internal Paperclip ticket id or instance-derived details