vercel/ai · error · APICallError
${error.message}
Error message
${error.message} What it means
When an Anthropic SSE stream reports a normalized error event, doStream re-throws it as an `APICallError` whose message is the provider's error message (the template `${error.message}`). This surfaces mid-stream provider failures (overloaded, rate limit, invalid request) with status code, headers, and the raw error data attached.
Source
Thrown at packages/anthropic/src/anthropic-language-model.ts:2769
let result = await firstChunkReader.read();
// when raw chunks are enabled, the first chunk is a raw chunk, so we need to read the next chunk
if (result.value?.type === 'raw') {
result = await firstChunkReader.read();
}
// The Anthropic API returns 200 responses when there are overloaded errors.
// We handle the case where the first chunk is an error here and transform
// it into an APICallError.
if (result.value?.type === 'error') {
const error = result.value.error;
if (!isProviderStreamError(error)) {
throw new Error('Expected a normalized Anthropic stream error');
}
throw new APICallError({
message: error.message,
url,
requestBodyValues: body,
statusCode: error.statusCode ?? 500,
responseHeaders,
responseBody: JSON.stringify(error.data),
isRetryable: error.isRetryable ?? false,
});
}
} finally {
firstChunkReader.cancel().catch(() => {});
firstChunkReader.releaseLock();
}
return {
stream: streamForConsumer,
request: { body },
response: { headers: responseHeaders },View on GitHub (pinned to 69428b1f8b)
Solutions
- Read the resulting APICallError's statusCode/message to identify the provider cause and adjust the request or retry accordingly.
- Catch the error via the stream's onError/onFinish callbacks or try/catch around the stream consumption.
- Enable retry/backoff for overloaded (529) and rate-limit (429) statuses.
- Check `error.data`/responseBody for Anthropic's error type field (overloaded_error, rate_limit_error, etc.).
Example fix
// before
const { textStream } = streamText({ model: anthropic('claude-...'), prompt });
for await (const t of textStream) process.stdout.write(t);
// after
const result = streamText({ model: anthropic('claude-...'), prompt, maxRetries: 3 });
try {
for await (const t of result.textStream) process.stdout.write(t);
} catch (e) {
if (APICallError.isInstance(e) && e.statusCode === 529) { /* retry later */ }
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
function isAnthropicStreamApiError(e: unknown): e is import('@ai-sdk/provider').APICallError {
return import('@ai-sdk/provider').APICallError.isInstance(e);
} Try / catch
try {
for await (const delta of result.textStream) { /* ... */ }
} catch (e) {
if (APICallError.isInstance(e)) {
const { statusCode, message } = e;
if (statusCode === 529 || statusCode === 429) { /* retry with backoff */ }
}
throw e;
} Prevention
- Set maxRetries on streamText for transient provider errors.
- Handle Anthropic error types (overloaded_error, rate_limit_error) explicitly.
- Monitor stream onError/onFinish for mid-stream failures.
- Keep model parameters within provider limits to avoid invalid_request errors.
When it happens
Trigger: Consuming `streamText`/stream APIs with an Anthropic model when the upstream stream emits an error event; the error must pass `isProviderStreamError` or a different error ('Expected a normalized Anthropic stream error') is thrown instead.
Common situations: Anthropic returning 529 overloaded_error mid-stream; rate_limit errors on long streams; invalid_request_error from unsupported parameters appearing after stream start; transient network drops interpreted as stream errors.
Related errors
- ${parsedError.value.error}
- Invalid JSON response
- [WorkflowAgent] Provider-executed tool "${toolCall.toolName}
- 'element streams in no-schema mode' functionality not suppor
- 'element streams in object mode' functionality not supported
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/4bcf28382fa7fa30.
Report an issue: GitHub.