From ecd066c8700955e3456dd9387e6b8317f024e26c Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Wed, 11 Nov 2026 14:34:58 +0100 Subject: [PATCH] fix: say why the login failed in the v2 authRequired error (#1598) ## Problem When an API request fails authentication, the v2 agent hides the message Claude Code writes for it (#1582) and fails the turn with a bare `Authentication required`. The reason is lost, for example: > Failed to authenticate: this login reached its time limit and cannot be renewed. Run `claude auth login` to sign in again, or use `claude setup-token` and set CLAUDE_CODE_OAUTH_TOKEN for unattended jobs A client can then only say that the agent is signed out, not why. ## Change The turn's `authRequired` error now carries the result's error text in its message: `Authentication required: `. The code and `data` are unchanged, so a client that starts its own sign-in from the code behaves as before. Text that tells the user to run `/login` is still left out, as that instruction is for Claude Code's terminal (#863). Only the v2 agent changes. ## Testing `npm run check`, `npm run build` and `npm run test:run` pass. The v2 tests now pin both messages: the plain one for the `/login` text, and the one with the reason for an authentication failure reported on the assistant message. Not checked against a real expired login. --- src/tests/v2/v2.test.ts | 4 ++-- src/v2/outcome.ts | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tests/v2/v2.test.ts b/src/tests/v2/v2.test.ts index 14c9446b..398aae4f 100644 --- a/src/tests/v2/v2.test.ts +++ b/src/tests/v2/v2.test.ts @@ -2433,7 +2433,7 @@ describe("ACP v2 core", () => { expect(client.sessionUpdates.at(-1)).toMatchObject({ state: "idle", stopReason: "error", - error: { code: -32000 }, + error: { code: -32000, message: "Authentication required" }, }); }); @@ -2442,7 +2442,7 @@ describe("ACP v2 core", () => { "an authentication failure as authRequired", "authentication_failed", "Failed to authenticate. API Error: 401", - { code: -32000 }, + { code: -32000, message: "Authentication required: Failed to authenticate. API Error: 401" }, ], [ "another failure with its error kind", diff --git a/src/v2/outcome.ts b/src/v2/outcome.ts index 26077e82..23cdb663 100644 --- a/src/v2/outcome.ts +++ b/src/v2/outcome.ts @@ -91,7 +91,11 @@ export function idleOutcome( providerFailureCategory(kind) === "auth_required"); return failed( authFailure - ? RequestError.authRequired() + ? // Claude Code's `/login` instruction is for its terminal, so that text + // is left out. Any other says why the login failed, e.g. "Failed to + // authenticate: this login reached its time limit and cannot be + // renewed." + RequestError.authRequired(undefined, ended.loginRequired ? undefined : ended.error) : RequestError.internalError(kind ? { errorKind: kind } : undefined, ended.error), ); }