can1357/oh-my-pi · error · BedrockApiError
exceptionType
exceptionType
Error message
${exceptionType}: ${errorMessage} What it means
Bedrock communicates mid-stream failures as event-stream messages with :message-type "exception". The library converts these into a BedrockApiError whose message is "<exceptionType>: <message>" and whose code is the exception type (e.g. ValidationException, ThrottlingException, AccessDeniedException, ModelStreamErrorException).
Source
Thrown at packages/ai/src/providers/amazon-bedrock.ts:508
response.status,
{
headers: response.headers,
},
);
}
if (!response.body) throw new AIError.BedrockApiError("Bedrock response has no body", response.status);
// Track first event for the abort/diagnostic path (currently informational).
for await (const message of decodeEventStream(response.body)) {
const messageType = message.headers[":message-type"];
const eventType = message.headers[":event-type"];
if (messageType === "exception") {
const exceptionType = message.headers[":exception-type"] || "Exception";
const payload = safeParsePayload(message.payload) as { message?: string } | undefined;
const errorMessage = payload?.message || new TextDecoder().decode(message.payload);
const text = `${exceptionType}: ${errorMessage}`;
throw new AIError.BedrockApiError(text, 400, { code: exceptionType });
}
if (messageType === "error") {
const code = message.headers[":error-code"] || "UnknownError";
const errorMessage = message.headers[":error-message"] || new TextDecoder().decode(message.payload);
throw new AIError.BedrockApiError(`${code}: ${errorMessage}`, 400, { code });
}
if (messageType !== "event") continue;
const payload = safeParsePayload(message.payload);
if (!payload) continue;
switch (eventType) {
case "messageStart": {
// no-op: first event marker is implicit by stream entry.
const ev = payload as MessageStartEvent;
if (ev.role !== "assistant") {
throw new AIError.BedrockApiError(
"Unexpected assistant message start but got user message start instead",View on GitHub (pinned to 9690622007)
Solutions
- Parse the exceptionType from the error code and branch: ThrottlingException → retry with backoff; AccessDeniedException → fix IAM/model access; ValidationException → fix request params
- Check the embedded message for the exact invalid field or reason
- Retry only idempotent-safe exceptions; ValidationException will not fix itself
- Verify model input size/token counts against the model's documented limits
Example fix
// before
catch (e) { alert(e.message); }
// after
catch (e) {
if (e.code === "ThrottlingException") return retryWithBackoff();
if (e.code === "AccessDeniedException") return fixIamPermissions();
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// validate inference params against model limits before the call
if (input.tokens > model.contextWindow) throw new Error("input exceeds model context window");
if (!allowedParams.every(p => p in input)) throw new Error("invalid inference parameter"); Type guard
function isBedrockStreamException(e: unknown): e is AIError.BedrockApiError & { code: string } {
return e instanceof AIError.BedrockApiError && typeof (e as { code?: unknown }).code === "string";
} Try / catch
try {
await streamBedrock(options);
} catch (e) {
if (isBedrockStreamException(e)) {
switch (e.code) {
case "ThrottlingException": return retryWithBackoff();
case "AccessDeniedException": return requestModelAccess();
case "ValidationException": throw new UserInputError(e.message); // do not retry
default: return maybeRetry(e);
}
}
throw e;
} Prevention
- Pre-validate token counts and inference parameters against the model's documented limits
- Retry only Throttling/5xx-class exceptions with exponential backoff
- Keep model access grants current — AccessDenied can appear mid-stream
- Handle partial output: streams can emit content before the exception
When it happens
Trigger: A 200-initiated event stream that then carries an exception message: invalid inference parameters (ValidationException), throttling, denied model access, corrupted model stream, internal server failures mid-generation.
Common situations: Requesting a context length over the model's limit; hitting account throughput limits mid-stream; model access revoked between call start and stream; model-side errors during long generations.
Related errors
- code
- Bedrock response has no body
- Bedrock HTTP ${response.status}: ${errBody.slice(0, 1000)}
- AbortError
- Unable to resolve AWS credentials. Configure static environm
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/cd703771bc6b1c5d.
Report an issue: GitHub.