fix(ai): surface provider HTTP error body instead of opaque SDK message

Add a shared normalizeProviderError helper in packages/ai/src/utils/error-body.ts
and route the 8 body-blind / status-only providers through it (amazon-bedrock,
azure-openai-responses, google, google-vertex, images/openrouter,
openai-codex-responses, openai-completions, openai-responses). Non-schema 4xx/5xx
responses from proxies / gateways now show the real reason carried in the response
body alongside the HTTP status, instead of "403 status code (no body)" or
"Unknown: UnknownError".

The helper probes status (statusCode, status, $metadata.httpStatusCode,
$response.statusCode) and body (body, parsed error object, $response.body) across
the Mistral, OpenAI, Google, and Bedrock SDK shapes, truncates the body at a 4000
char cap, and preserves error.message when the SDK already folded the body in
(Anthropic / Google happy path). mistral.ts and anthropic.ts are left untouched.
Provider prefixes and the OpenRouter metadata.raw append are preserved.

closes #5763
This commit is contained in:
Stephan Schneider
2026-06-17 09:21:03 +02:00
parent d7868b0998
commit 62fad94f1a
12 changed files with 580 additions and 36 deletions
+2 -1
View File
@@ -24,6 +24,7 @@ import type {
ThinkingContent,
ToolCall,
} from "../types.ts";
import { formatProviderError, normalizeProviderError } from "../utils/error-body.ts";
import { AssistantMessageEventStream } from "../utils/event-stream.ts";
import { providerHeadersToRecord } from "../utils/headers.ts";
import { getProviderEnvValue } from "../utils/provider-env.ts";
@@ -288,7 +289,7 @@ export const stream: StreamFunction<"google-vertex", GoogleVertexOptions> = (
}
}
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
output.errorMessage = formatProviderError(normalizeProviderError(error));
stream.push({ type: "error", reason: output.stopReason, error: output });
stream.end();
}