pingdotgg / pingdotgg/t3code

[Bug]: Claude auth failure renders as plain result text with no re-login affordance

Open
#7,878 2 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
23k
Forks
5.9k
Avg merge
11h 14m
Merged PRs (30d)
357

Description

Before submitting
  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.
Area

apps/web

Steps to reproduce
  1. Have the Claude provider working in T3 Code.
  2. Log out of Claude Code in a terminal (claude auth logout, or /logout in the CLI). An OAuth session that expires and fails to refresh produces the same state.
  3. Send a message in an existing T3 thread on the Claude provider.
Expected behavior

T3 recognizes this as an authentication failure and surfaces something actionable: a "Claude is signed out" state with a log-in action (or at minimum a pointer to Settings → Providers and the CLI command), and the provider marked unauthenticated.

The failure is distinguishable from a normal failed turn, so the user knows the fix is re-authentication rather than a retry.

Actual behavior

The turn ends with the SDK's raw result string rendered as the assistant's reply:

Failed to authenticate: OAuth session expired and could not be refreshed

That is the entire response. The only affordance on it is the "Copy to clipboard" hover button. There is no log-in action, no link to provider settings, no retry, and nothing indicating the problem is outside the app. A user who does not already know to open a terminal and re-run claude auth login has no path forward from inside T3 — which matters most on mobile / T3 Connect, where there is no terminal to go to.

The information needed to do better is already present. The SDK marks this failure distinctly:

{"error":"authentication_failed","is_api_error_message":true}
{"result":"Failed to authenticate: OAuth session expired and could not be refreshed","type":"result"}

Grepping the shipped desktop bundle for OAuth session expired returns zero matches, so the string is passed through verbatim and nothing in T3 classifies it. This looks like a missing branch on error === "authentication_failed" rather than missing detection. The marker may need to be plumbed from the provider adapter in apps/server for the web timeline to render a distinct state.

Impact

Major degradation or frequent failure

Version or commit

T3 Code Nightly 0.0.34-nightly.20260819.1133

Environment

macOS 26.6.1 (Darwin 25.6.0) arm64, T3 Code Nightly 0.0.34-nightly.20260819.1133, Claude Code 2.1.239, Claude provider on claude.ai Max OAuth

Logs or stack traces
{"error":"authentication_failed","is_api_error_message":true}
{"result":"Failed to authenticate: OAuth session expired and could not be refreshed","type":"result"}
Screenshots, recordings, or supporting files

The thread shows the user's prompt, then a single unstyled line reading ...uthenticate: OAuth session expired and could not be refreshed, with a "Copy to clipboard" tooltip overlapping the start of the text. No other controls are rendered.

Workaround

Re-authenticate in a terminal (claude auth login), then start a new thread or restart T3 — per #6022, open threads hold stale sessions and keep reporting the old auth state after credentials are fixed.


Related, but distinct:

  • #6022 — a cause that produces this same string (credentials wiped, refresh token destroyed). This issue is about how the failure is presented, whatever the cause.
  • #7690 — Settings reports Claude authenticated while the launched CLI is logged out.
  • #4225 — prompting a logged-out Claude makes the user's message invisible in the GUI.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in apps/web and trace how the timeline renders provider results, then follow the provider adapter in apps/server to see whether the SDK's error value is preserved. Use the authentication_failed marker to distinguish this failure from a normal failed turn and expose an actionable re-login or provider-settings path. Done means the provider is marked unauthenticated and the web UI no longer renders the raw result as the assistant reply.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
authentication, backend, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
64/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.