fix(ai): classify AWS modeled errors from every restJson1 identity location (#58770)

This commit is contained in:
Aiden Cline
2026-10-24 18:14:40 -05:00
committed by GitHub
Unverified
parent bd2ba0a685
commit 252ed4a2d8
2 changed files with 33 additions and 0 deletions
+10
View File
@@ -250,6 +250,7 @@ export function classifyProviderFailure(input: ProviderFailure): AIError["reason
...providerCodes(body),
...providerCodes(input.message),
...(GATEWAY_CODE_LABEL.exec(input.message)?.slice(1) ?? []),
...awsErrorType(input.http?.headers["x-amzn-errortype"]),
].map((code) => code.toLowerCase())
// Scan the raw payload too so signals missing from the summary message
// (e.g. overflow phrases nested in a JSON error body) still classify.
@@ -325,6 +326,8 @@ function providerCodes(value: unknown) {
const exception = isRecord(decoded.exception) ? decoded.exception : undefined
return [
decoded.code,
...awsErrorType(decoded.__type),
...awsErrorType(decoded.code),
// Stability's `{ id, name, errors }` bodies carry the code in `name`.
Array.isArray(decoded.errors) ? decoded.name : undefined,
decoded.error_type,
@@ -343,3 +346,10 @@ function providerCodes(value: unknown) {
exception?.type,
].filter((value): value is string => typeof value === "string")
}
// AWS restJson1 reports the modeled error in `X-Amzn-Errortype`, `__type` or `code`, possibly
// namespaced (`ns#Name`) or suffixed (`Name:uri`). Keep the shape name only.
// https://smithy.io/2.0/aws/protocols/aws-restjson1-protocol.html#operation-error-serialization
function awsErrorType(value: unknown) {
return typeof value === "string" ? [value.replace(/:.*/s, "").replace(/^[^#]*#/, "")] : []
}
+23
View File
@@ -75,6 +75,29 @@ describe("RequestExecutor", () => {
}),
)
it.effect("classifies AWS modeled errors from every restJson1 identity location", () =>
Effect.sync(() => {
const cases = [
{ body: { code: "ThrottlingException" } },
{ body: { __type: "ThrottlingException" } },
{ body: { code: "com.amazonaws.bedrock#ThrottlingException:http://internal.amazon.com/coral/" } },
{ body: {}, headers: { "X-Amzn-Errortype": "ThrottlingException:http://internal.amazon.com/coral/" } },
]
for (const item of cases) {
const body = JSON.stringify({ ...item.body, message: "Slow down" })
const error = RequestExecutor.httpFailure({
message: "Slow down",
url: request.url,
status: 400,
responseHeaders: item.headers,
responseBody: body,
})
expect(error.reason._tag).toBe("RateLimit")
expect(error.reason.body).toBe(body)
}
}),
)
it.effect("retains the original body-read failure on an HTTP status error", () =>
Effect.gen(function* () {
const cause = new Error("response body disconnected")