Repository navigation
fix(bedrock-passthrough)!: return AWS-shaped errors so AWS SDKs read the code and message - #46522
Conversation
…he code and message A guardrail block on a /bedrock route now answers with x-amzn-errortype ValidationException and a top-level message, and an error Bedrock returned (such as a 429 ThrottlingException) is passed through with its status, x-amzn-errortype and body
…k replacements unchanged
…ls keep the litellm error
…ed content as ValidationException
…ead of copying its fields Unit tests drive the error response with the real request processor and ProxyLogging
…auth, budget and rate-limit errors
|
@litereview code-review |
✅ code-review5/5 · Ready for human reviewScope: full · Full PR review. Completed · Some checks not run. No correctness findings. The change adds A Checks and execution details
View review · Reviewed |
Merging this PR will not alter performance
|
…eration returned A guardrail service's HTTP error that carries x-amzn-errortype keeps the litellm error
|
@litereview code-review |
|
bugbot run |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
@litereview full |
✅ fullScope: full · Full PR review. Completed · Some checks not run. Verdict: no actionable defects foundI didn't find a failure I could pin to the changed code. The change is limited to the two Bedrock model-operation handlers, which both now catch errors through This verdict comes from reading the code and running the unit tests. I didn't run a proxy, so none of it was observed live. Who uses what changed
Contract note (deliberate, not a defect)When Bedrock itself rejects a request on
Verification
Not verified
Checks and execution details
View review · Reviewed |
| return None | ||
|
|
||
|
|
||
| _BEDROCK_MODEL_OPERATION_PATH: Final = re.compile(rb"/model/[^/?]+/[^/?]+(?:$|\?)") |
There was a problem hiding this comment.
non blocking nit: guessing bedrock vs guardrail from the url feels fragile, could the passthrough call tag its own errors as bedrock instead
…rough raises them instead of matching the URL A guardrail service's HTTP error never goes through the passthrough call, so it keeps the litellm error whatever its URL
|
Automatic reviews are disabled for this repository. |
|
@litereview code-review |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 49056bd. Configure here.
|
@litereview code-review |
litellm-stampbot: risk lowApproved at Rules (
Judge (gpt-6-luna): low, probability of high 0.28 (high at or above 0.75)
Pushes do not re-run this check. Comment |
litellm-stampbot
left a comment
There was a problem hiding this comment.
Low risk by rule and by judgement at 49056bd
…held block before the first frame Main's AWS-shaped passthrough errors (#46522) answer a guardrail block before the first frame with x-amzn-errortype ValidationException, so boto3 reads the code and the guardrail message instead of a bare 400.
TLDR
Problem this solves:
ClientError (400)with an empty message(429)with an empty message, and the SDK never retries itHow it solves it:
x-amzn-errortype: ValidationExceptionand a top-levelmessageIntentional product change: AWS SDKs in standard or legacy retry mode now retry Bedrock throttling through the proxy, as they do against Bedrock directly
User Flow
Before: an app using the AWS SDK through the proxy gets errors with no code and no message
converseorconverse_streamwithendpoint_url=https://litellm-domain/bedrockand a LiteLLM keyClientError: An error occurred (400) when calling the Converse operation:with an empty message(400)or(429)with an empty message and does not retry the 429After: the same app sees the errors it would get from Bedrock
ValidationExceptionwith the guardrail's message, e.g.Violated guardrail policyValidationExceptionorThrottlingExceptionwith Bedrock's message, after its normal retriesLinear ticket
Resolves LIT-9617
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/unit/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or moreDelays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Setup: proxy with 4 workers and Postgres, every edge real, no stand-ins. Model
claude-haiku=bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0and modelpixtral=bedrock/us.mistral.pixtral-large-2502-v1:0, both on real Bedrock (us-east-1). Throttling is real Bedrock throttling: a script sends large requests straight to AWS until this account's Pixtral Large token quota is used up, then the client call goes through the proxy. Keys: one with a real AWS Bedrock guardrail aspre_call(wordzzzforbiddenblocked), one with a real Akto guardrail aspost_call(its policy blocks emails in replies), one with no guardrail. Clients: AWS CLI 1.45.41 withAWS_BEARER_TOKEN_BEDROCK=<LiteLLM key>and--endpoint-url http://<proxy>/bedrock, and boto3 1.43.1converse_streamThe same cases on the direct model id route (
--model-id us.anthropic.claude-haiku-4-5-20251001-v1:0with aus.anthropic.*deployment), and with a real Noma guardrail aspre_callorduring_call, give the same Before and AfterBefore (2d4472e)
Guardrail blocks the prompt, AWS CLI converse
aws bedrock-runtime converse --endpoint-url http://127.0.0.1:4982/bedrock --model-id claude-haiku --messages '[{"role":"user","content":[{"text":"tell me about zzzforbidden"}]}]'with the Bedrock guardrail keyAn error occurred (400) when calling the Converse operation:with no messageBedrock rejects the request, AWS CLI converse
"text":"hi"and--inference-config temperature=5An error occurred (400) when calling the Converse operation:with no messageBedrock throttles, AWS CLI converse
AWS_RETRY_MODE=standard AWS_MAX_ATTEMPTS=3 aws bedrock-runtime converse ... --model-id pixtral --messages file://big-prompt.jsonwith the no-guardrail keyAn error occurred (429) when calling the Converse operation:with no messageGuardrail blocks the reply before the first frame, boto3 converse_stream
client.converse_stream(modelId="claude-haiku", ...)asking for a reply with an email address, with the Akto keyClientError: An error occurred (403) when calling the ConverseStream operation:,Code='403' Message=''The proxy admin opens the blocked request in the Logs page
[Block] Sorry, the model cannot answer this question. This has been blocked by PII-Data policy., guardrailakto-postAfter (49056bd)
Guardrail blocks the prompt, AWS CLI converse
An error occurred (ValidationException) when calling the Converse operation: Violated guardrail policyBedrock rejects the request, AWS CLI converse
An error occurred (ValidationException) when calling the Converse operation: 1 validation error detected: Value '5.0' at 'inferenceConfig.temperature' failed to satisfy constraint: Member must have value less than or equal to 1Bedrock throttles, AWS CLI converse
An error occurred (ThrottlingException) when calling the Converse operation (reached max retries: 2): Too many tokens, please wait before trying again.Guardrail blocks the reply before the first frame, boto3 converse_stream
ClientError: An error occurred (ValidationException) when calling the ConverseStream operation: [Block] Sorry, the model cannot answer this question. This has been blocked by PII-Data policy.,Code='ValidationException'with the same messageThe proxy admin opens the blocked request in the Logs page
akto-post: logging is unchangedType
🐛 Bug Fix
Behavior changes
Removed / renamed
Changed on
/bedrock/model/<model>/...(converse, converse-stream, invoke, invoke-with-response-stream)errorobject, plus a top-levelmessageandx-amzn-errortype: ValidationExceptionx-amzn-errortype: Bedrock's own status, body,x-amzn-errortypeandcontent-type, replacing{"detail": {"error": "<Bedrock body as a string>"}}ThrottlingExceptionand retry, so one client call can reach Bedrock up to the SDK's max attemptsUnchanged
x-amzn-errortype/bedrockagent-runtime routes, count-tokensCaveats (if any)
Medium
ValueErrorkeep LiteLLM's bodyValidationExceptionLow
llm_provider-x-amzn-requestid, so boto3'sRequestIdstays empty/bedrockpaths keep{"detail": ...}Final Attestation
Ran /live-pr-risk at 49056bd with real edges only (real Bedrock and real Bedrock throttling, real AWS Bedrock guardrail, Akto and Noma, 4 workers, base 2d4472e vs head): no regressions. The backward-incompatible changes it found are exactly the ones listed in Behavior changes. A 40-request burst with a worker killed mid-burst behaved as on base apart from the intended error shapes, with the same failure-row counts per key, over eight rounds per leg at b6c0e20 and two more on 49056bd. The paused-Postgres cell ran at bd884cb, before later commits that do not touch that path
REVIEWER MUST KNOW BEFORE APPROVING
errorobject and gains a top-levelmessageplusx-amzn-errortype: ValidationExceptionx-amzn-errortypeandcontent-type, replacing{"detail": {"error": "<string>"}}, so a client that parseddetailbreaksNote
Medium Risk
Changes Bedrock passthrough error response contracts (raw Bedrock bodies vs
detailwrapping) and enables AWS SDK retries on throttling; guardrail vendor failures may be surfaced asValidationExceptionin edge cases.Overview
Bedrock passthrough errors are reshaped so boto3/AWS CLI can read
x-amzn-errortypeand a top-levelmessage, instead of emptyClientErrorcodes/messages.Passthrough HTTP failures from the upstream provider are tagged via
raise_for_provider_status/is_provider_error. On/bedrock/model/..., real Bedrock errors (withx-amzn-errortype) are returned with Bedrock’s status, body, and headers; guardrail blocks (pre/post-call, PII, stamped HTTPException details) becomeValidationExceptionthroughAwsErrorTypeProxyExceptionand a dedicated FastAPI handler that merges LiteLLM’serrorpayload with AWS fields. Auth, budget, proxy rate limits, unknown models, and non-Bedrock passthrough routes stay on the existing LiteLLM error shape.Intentional behavior: SDK retry logic now sees
ThrottlingExceptionon proxied Bedrock 429s, so one client call may hit upstream multiple times (same as calling Bedrock directly).Reviewed by Cursor Bugbot for commit 49056bd. Bugbot is set up for automated code reviews on this repo. Configure here.