Skip to content

[Bug]: BedrockGuardrail streaming hook drops HTTPException after HTTP 200, producing broken SSE stream #26387

@orolega

Description

@orolega

Check for existing issues

  • I have searched the existing issues and checked that my issue is not a duplicate.

What happened?

Description

When a Bedrock guardrail hard-blocks a streamed response,
async_post_call_streaming_iterator_hook raises an HTTPException inside
the async generator body. By the time the guardrail runs, the HTTP 200
header has already been written to the client — the exception cannot be
converted to a 4xx response. Instead it propagates up, truncating the SSE
stream mid-flight. The client receives a partial or malformed response with
no indication of why.

Expected behaviour

The client receives a well-formed SSE error frame followed by [DONE]:

data: {"error": {"message": "Violated guardrail policy", "code": 400, "type": "guardrail_violation"}}

data: [DONE]

Actual behaviour

The HTTPException escapes the generator. The stream is truncated and the
client has no structured error to parse.

Root cause

async_post_call_streaming_iterator_hook has no try/except around the
make_bedrock_api_request / asyncio.gather calls. Both the parallel
INPUT+OUTPUT path (should_validate_input=True) and the output-only path
(should_validate_input=False) are affected.

GuardrailInterventionNormalStringError (soft-block /
disable_exception_on_block=True) is not affected — it is already
caught by inner try/except blocks.

Fix

Wrap the Bedrock validation block in a try/except HTTPException and yield
two in-band SSE frames instead of letting the exception escape.

Steps to Reproduce

  1. Configure a BedrockGuardrail with event_hook: post_call (or during_call).
  2. Set disable_exception_on_block to false (the default).
  3. Send a streaming request whose output triggers a hard-block policy
    (e.g. topic policy, content policy — anything that returns action: BLOCKED).
  4. Observe the SSE stream terminates abruptly without an error frame.

Relevant log output

What part of LiteLLM is this about?

Proxy

What LiteLLM version are you on ?

v1.83.7

Twitter / LinkedIn details

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions