Skip to content

fix(server): respawn Claude after an expired login - #9468

Open
robertnisipeanu wants to merge 1 commit into
pingdotgg:mainfrom
robertnisipeanu:worktree-claude-auth-respawn
Open

fix(server): respawn Claude after an expired login#9468
robertnisipeanu wants to merge 1 commit into
pingdotgg:mainfrom
robertnisipeanu:worktree-claude-auth-respawn

Conversation

@robertnisipeanu

@robertnisipeanu robertnisipeanu commented Sep 3, 2026

Copy link
Copy Markdown

Fixes #9607

Problem

Claude Code loads its OAuth credentials once per process. T3 Code keeps one long-lived CLI per thread, so after the credentials expire that thread keeps answering "Not logged in · Please run /login" even after the user logs in again from a terminal. New threads work because they spawn a fresh CLI. The stuck thread only recovers once the idle reaper kills its process, up to 30 minutes later, or after a manual Stop.

Fix

When the CLI reports an assistant message with error: "authentication_failed", the Claude adapter:

  • fails the turn with the CLI's own message (a message without text gets a runtime error with a fixed fallback instead), and
  • stops the session at the end of that turn, so the next send recovers the thread from its persisted resume cursor and spawns a fresh CLI with the current credentials.

The stop runs on the stream fiber itself, so stopSessionInternal skips interrupting that fiber and lets the stream end through its own stopped check. The first auth-failure message in a turn wins, so a repeated failure does not duplicate the runtime error or replace the CLI's message with the fallback.

Testing

  • vp test run apps/server/src/provider/Layers/ClaudeAdapter.test.ts (81 passed, two new tests: auth failure with text, and repeated auth failure without text)
  • server typecheck, lint, and format on the touched files

Built with Claude Fable 5.1 in Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Changes Claude session lifecycle and turn completion on auth errors; incorrect handling could drop sessions prematurely or leave stale CLI processes, but behavior is scoped to authentication_failed and covered by new tests.

Overview
Fixes threads stuck on “Not logged in” after the user re-authenticates by treating Claude CLI authentication_failed assistant messages as a hard session failure and tearing down the long-lived process so the next message spawns a fresh CLI with current credentials.

The Claude adapter records the first auth failure per turn in authenticationError, fails the turn with the CLI’s text (or a runtime.error plus fallback when there is no text), skips duplicating that message as a generic runtime error, and calls stopSessionInternal after turn.completed. stopSessionInternal no longer interrupts the stream fiber when stop is invoked from that same fiber, avoiding a self-deadlock while the session exits.

Tests cover auth failure with CLI text (failed turn, session.exited, no session, one close) and repeated empty auth messages (single runtime error, first message wins).

Reviewed by Cursor Bugbot for commit 5222edf. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix ClaudeAdapter to handle expired-login failures and stop the session

  • Adds an authentication-error field to ClaudeSessionContext that stores the first authentication-failed message text from the Claude CLI per turn/session
  • When an assistant message is marked authentication_failed, the handler in ClaudeAdapter.ts extracts and stores its text once; textless failures emit a single runtime.error with a fallback message and repeated failures are suppressed
  • The result handler gives the recorded auth failure precedence over the SDK result status, completes the turn as failed with that message, stops the session, and avoids emitting a duplicate runtime.error
  • stopSessionInternal now skips interrupting the stream fiber when shutdown is invoked from that same fiber, while still interrupting a distinct live stream fiber
  • Behavioral Change: an SDK result following an authentication failure now always completes the turn as failed and stops the session, even when the SDK result subtype is success

Macroscope summarized 5222edf.

Claude Code loads its OAuth credentials once per process. After they
expire, the long-lived CLI behind a thread keeps answering "Not logged
in" even once the user has run /login elsewhere, until the idle reaper
kills it.

When the CLI reports an assistant message with error
"authentication_failed", the adapter fails the turn with the CLI's
message and stops the session, so the next turn spawns a fresh CLI with
the current credentials.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 3, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The production Claude adapter now changes authentication-failure handling and terminates sessions so later turns can respawn with refreshed credentials. Because this is an authentication-related runtime lifecycle change, it requires human review despite its focused scope and targeted tests.

You can add or adjust custom eligibility rules. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Claude thread stays logged out after re-login until its CLI process is reaped

1 participant