Skip to content

fix(bedrock): unify streaming error handling for in-band and out-of-band errors#1479

Open
sevakva wants to merge 4 commits into
anthropics:mainfrom
sevakva:fix/bedrock-streaming-errors
Open

fix(bedrock): unify streaming error handling for in-band and out-of-band errors#1479
sevakva wants to merge 4 commits into
anthropics:mainfrom
sevakva:fix/bedrock-streaming-errors

Conversation

@sevakva
Copy link
Copy Markdown

@sevakva sevakva commented Apr 30, 2026

Summary

Closes #1472. Closes #1477. Supersedes #1475, #1485, #1486, #1488

Two stream-error paths in lib/bedrock failed to surface as typed APIStatusError subclasses. This PR routes both through the existing event="error" SSE path and adds a body-aware exception dispatch.

Bugs

#1472 — HTTP 200 stream where the first SSE chunk is an in-band error envelope ({"type":"error","error":{...}}), reliably reproducible with cross-region inference profiles. The decoder hardcoded event="completion", so the streaming layer parsed it as RawMessageStartEvent(message=None) and crashed with AttributeError: 'NoneType' object has no attribute 'model'.

#1477 — Out-of-band exception frame (:message-type: exception with a :exception-type header). botocore parses these with status_code != 200. The decoder raised a bare ValueError, uncatchable as APIStatusError.

Bundled: HTTP 529 → OverloadedError, matching anthropic._client.

Changes

Decoder normalizes both shapes into event="error" and translates Bedrock :exception-type to the Anthropic error.type:

:exception-type error.type Class
throttlingException rate_limit_error RateLimitError
serviceUnavailableException overloaded_error OverloadedError
internalServerException api_error InternalServerError
modelStreamErrorException api_error InternalServerError
modelTimeoutException api_error InternalServerError
validationException invalid_request_error BadRequestError

Unknown types pass through verbatim → generic APIStatusError. The event status_code is not used for class selection (botocore hardcodes it to 400 for any exception frame); :exception-type is the source of truth.

Client_make_status_error gains a body-aware pre-dispatch keyed on body.error.type. This is what lets in-band HTTP 200 errors reach the right subclass. The lookup table uses ErrorType literals from anthropic.types.shared.

The body dispatch is additive — non-stream 4xx/5xx already produce the correct subclass via HTTP status; the new path only kicks in when the body carries an error.type the status fallback would miss.

Tests

  • tests/lib/test_bedrock_stream_decoder.py — decoder unit tests, parametrized over the full mapping table.
  • tests/lib/streaming/test_bedrock_stream_errors.py — E2E via httpx.MockTransport with hand-encoded eventstream frames, sync + async, plus 529 parity.

sevakva added 2 commits April 30, 2026 11:10
Two streaming error paths previously failed to surface as typed
APIStatusError subclasses:

- HTTP 200 streams where the first SSE chunk is an in-band error frame
  (e.g. cross-region inference profile rate limits). The decoder
  hardcoded event="completion", so the streaming layer parsed the
  payload as RawMessageStartEvent with message=None and crashed with
  AttributeError (anthropics#1472).
- Out-of-band stream errors where botocore parses an EventStreamMessage
  with status_code != 200 and a :exception-type header (e.g.
  internalServerException, throttlingException). The decoder raised a
  bare ValueError that bypassed retry/error handling (anthropics#1477).

Funnel both shapes through the existing event="error" SSE path:

- Decoder normalizes Bedrock :exception-type into Anthropic error.type
  (throttlingException → rate_limit_error,
  serviceUnavailableException → overloaded_error,
  internalServerException/modelStreamError/modelTimeout → api_error,
  validationException → invalid_request_error). Unknown types pass
  through verbatim and fall back to a generic APIStatusError.
- _make_status_error gains a body-aware pre-dispatch on
  body.error.type so in-band errors on HTTP 200 select the right
  exception class (RateLimitError, OverloadedError, etc.) instead of
  being misclassified as success.
- HTTP 529 → OverloadedError, matching anthropic._client behavior.
@sevakva
Copy link
Copy Markdown
Author

sevakva commented May 7, 2026

@localden Hello! Not sure who to ask, but is this repo alive? Do I need do anything extra? These issues with bedrock is really critical for our company and blocking us from using it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant