diff --git a/packages/core/src/common/llm-error.ts b/packages/core/src/common/llm-error.ts index 95f32558..4ccec015 100644 --- a/packages/core/src/common/llm-error.ts +++ b/packages/core/src/common/llm-error.ts @@ -102,10 +102,19 @@ function getErrorDetails(error: unknown, depth: number, seen: Set): LlmE } function getProviderMessage(error: unknown): string | undefined { - if (!isRecord(error) || !isRecord(error.error)) { + if (!isRecord(error)) { return undefined; } - return safeText(error.error.message); + // Providers and gateways do not agree on the error payload shape: some send + // an object with `message`, others send the message as a plain string. + const payload = error.error; + if (typeof payload === "string") { + return safeText(payload); + } + if (!isRecord(payload)) { + return undefined; + } + return safeText(payload.message); } function getHeader(headers: unknown, name: string): string | undefined { diff --git a/packages/core/src/tests/llm-error.test.ts b/packages/core/src/tests/llm-error.test.ts index a5a3e1ca..8fd92516 100644 --- a/packages/core/src/tests/llm-error.test.ts +++ b/packages/core/src/tests/llm-error.test.ts @@ -22,6 +22,18 @@ test("describeLlmError shows provider business errors with trace metadata", () = ); }); +test("describeLlmError keeps provider errors whose payload is a plain string", () => { + const error = Object.assign(new Error("502 Bad Gateway"), { + status: 502, + error: "Gateway failed", + headers: new Headers({ + "x-request-id": "request-789", + }), + }); + + assert.equal(describeLlmError(error), "HTTP 502: Gateway failed [request ID: request-789]"); +}); + test("describeLlmError unwraps underlying network causes", () => { const cause = new Error("getaddrinfo ENOTFOUND api.deepseek.com"); const error = Object.assign(new Error("Connection error."), { cause });