can1357/oh-my-pi · error · BedrockApiError
code
code
Error message
${code}: ${errorMessage} What it means
Bedrock event streams can carry :message-type "error" frames carrying an :error-code and :error-message (or raw payload). The library raises a BedrockApiError formatted "<code>: <message>" with the error code attached, using status 400 since the stream already started successfully.
Source
Thrown at packages/ai/src/providers/amazon-bedrock.ts:513
}
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",
0,
);
}
stream.push({ type: "start", partial: output });
break;View on GitHub (pinned to 9690622007)
Solutions
- Read the attached code to classify: retryable service errors → retry with backoff
- Inspect the message body for AWS's diagnostic detail
- Check the AWS health dashboard if failures cluster in time
- Capture and report persistent error codes to AWS support with request ids
Example fix
// before
for await (const chunk of stream) { use(chunk); } // throws mid-iteration
// after
try {
for await (const chunk of stream) use(chunk);
} catch (e) {
if (e.code && e.status === 400) logBedrockStreamError(e.code, e.message);
throw e;
} Defensive patterns
Strategy: try-catch
Type guard
function isBedrockStreamError(e: unknown): e is AIError.BedrockApiError & { code: string } {
return e instanceof AIError.BedrockApiError && typeof (e as { code?: unknown }).code === "string" && e.status === 400;
} Try / catch
try {
for await (const ev of streamBedrock(options)) consume(ev);
} catch (e) {
if (isBedrockStreamError(e)) {
log.warn("bedrock in-stream error", { code: e.code, message: e.message });
if (RETRYABLE.has(e.code)) return retryWithBackoff();
}
throw e;
} Prevention
- Maintain a retryable-code set derived from observed error codes
- Preserve any partial output emitted before the error frame
- Correlate failures with AWS health events before escalating
- Include the error code in user-facing telemetry for faster triage
When it happens
Trigger: In-stream error frames sent by Bedrock or the event-stream encoder (e.g. service unavailable mid-stream, deserialization failures, internal errors after the 200 response).
Common situations: Model infrastructure failures during generation; networking middleboxes injecting error frames; account-level service events interrupting streams.
Related errors
- exceptionType
- 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/fde4b2c48437c868.
Report an issue: GitHub.