{"record":{"id":"cd703771bc6b1c5d","repo":"can1357/oh-my-pi","slug":"exceptiontype","errorCode":"exceptionType","errorMessage":"${exceptionType}: ${errorMessage}","messagePattern":"\\$\\{exceptionType\\}: \\$\\{errorMessage\\}","errorType":"exception","errorClass":"BedrockApiError","httpStatus":400,"severity":"error","filePath":"packages/ai/src/providers/amazon-bedrock.ts","lineNumber":508,"sourceCode":"\t\t\t\t\tresponse.status,\n\t\t\t\t\t{\n\t\t\t\t\t\theaders: response.headers,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!response.body) throw new AIError.BedrockApiError(\"Bedrock response has no body\", response.status);\n\n\t\t\t// Track first event for the abort/diagnostic path (currently informational).\n\t\t\tfor await (const message of decodeEventStream(response.body)) {\n\t\t\t\tconst messageType = message.headers[\":message-type\"];\n\t\t\t\tconst eventType = message.headers[\":event-type\"];\n\n\t\t\t\tif (messageType === \"exception\") {\n\t\t\t\t\tconst exceptionType = message.headers[\":exception-type\"] || \"Exception\";\n\t\t\t\t\tconst payload = safeParsePayload(message.payload) as { message?: string } | undefined;\n\t\t\t\t\tconst errorMessage = payload?.message || new TextDecoder().decode(message.payload);\n\t\t\t\t\tconst text = `${exceptionType}: ${errorMessage}`;\n\t\t\t\t\tthrow new AIError.BedrockApiError(text, 400, { code: exceptionType });\n\t\t\t\t}\n\t\t\t\tif (messageType === \"error\") {\n\t\t\t\t\tconst code = message.headers[\":error-code\"] || \"UnknownError\";\n\t\t\t\t\tconst errorMessage = message.headers[\":error-message\"] || new TextDecoder().decode(message.payload);\n\t\t\t\t\tthrow new AIError.BedrockApiError(`${code}: ${errorMessage}`, 400, { code });\n\t\t\t\t}\n\t\t\t\tif (messageType !== \"event\") continue;\n\n\t\t\t\tconst payload = safeParsePayload(message.payload);\n\t\t\t\tif (!payload) continue;\n\n\t\t\t\tswitch (eventType) {\n\t\t\t\t\tcase \"messageStart\": {\n\t\t\t\t\t\t// no-op: first event marker is implicit by stream entry.\n\t\t\t\t\t\tconst ev = payload as MessageStartEvent;\n\t\t\t\t\t\tif (ev.role !== \"assistant\") {\n\t\t\t\t\t\t\tthrow new AIError.BedrockApiError(\n\t\t\t\t\t\t\t\t\"Unexpected assistant message start but got user message start instead\",","sourceCodeStart":490,"sourceCodeEnd":526,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/providers/amazon-bedrock.ts#L490-L526","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ncatch (e) { alert(e.message); }\n// after\ncatch (e) {\n  if (e.code === \"ThrottlingException\") return retryWithBackoff();\n  if (e.code === \"AccessDeniedException\") return fixIamPermissions();\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// validate inference params against model limits before the call\nif (input.tokens > model.contextWindow) throw new Error(\"input exceeds model context window\");\nif (!allowedParams.every(p => p in input)) throw new Error(\"invalid inference parameter\");","typeGuard":"function isBedrockStreamException(e: unknown): e is AIError.BedrockApiError & { code: string } {\n  return e instanceof AIError.BedrockApiError && typeof (e as { code?: unknown }).code === \"string\";\n}","tryCatchPattern":"try {\n  await streamBedrock(options);\n} catch (e) {\n  if (isBedrockStreamException(e)) {\n    switch (e.code) {\n      case \"ThrottlingException\": return retryWithBackoff();\n      case \"AccessDeniedException\": return requestModelAccess();\n      case \"ValidationException\": throw new UserInputError(e.message); // do not retry\n      default: return maybeRetry(e);\n    }\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["aws","bedrock","streaming","api-error"],"backgroundTag":"bedrock-stream-exception","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}