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: <text>`. 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.
This commit is contained in:
Ben Brandt
2026-11-11 14:34:58 +01:00
committed by GitHub
parent a22a797db2
commit ecd066c870
2 changed files with 7 additions and 3 deletions

View File

@@ -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",

View File

@@ -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),
);
}