Skip to content

fix(bedrock): forward provider response headers on chat completions - #37003

Merged
mateo-berri merged 5 commits into
litellm_internal_stagingfrom
litellm_forward_bedrock_response_headers
Aug 21, 2026
Merged

fix(bedrock): forward provider response headers on chat completions#37003
mateo-berri merged 5 commits into
litellm_internal_stagingfrom
litellm_forward_bedrock_response_headers

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Bedrock responses dropped x-amzn-requestid on /chat/completions
  • Broke request correlation with AWS when debugging
  • Affected converse (both modes) and invoke streaming

How it solves it:

  • Converse non-streaming now surfaces the provider's headers
  • Converse and invoke streaming carry them to the caller
  • Generic HTTP streaming path forwards them too

User Flow

Before: a developer debugging a slow Bedrock deployment can't get the AWS request id back out of the gateway, so AWS support has nothing to look up

  1. The proxy admin sets return_response_headers: true and points a model at bedrock/converse/us.anthropic.claude-haiku-4-5-20251001-v1:0
  2. The developer sends POST http://localhost:4000/v1/chat/completions with that model and reads the response headers
  3. The response is 200 with a normal completion, but carries no llm_provider-* headers at all, so there is no AWS request id to hand to support
  4. Same thing with "stream": true, and same thing again for a bedrock/invoke/... model with "stream": true

After: the same requests come back with the AWS request id in the response headers

  1. The proxy admin sets return_response_headers: true and points a model at bedrock/converse/us.anthropic.claude-haiku-4-5-20251001-v1:0
  2. The developer sends POST http://localhost:4000/v1/chat/completions with that model and reads the response headers
  3. The response now includes llm_provider-x-amzn-requestid: 836b894b-b89a-40e2-8522-532c4e71f882, which they can quote verbatim to AWS support
  4. Same for "stream": true, and for bedrock/invoke/... in both streaming and non-streaming, which also exposes the x-amzn-bedrock-* token and latency headers

Relevant issues

Linear ticket

Resolves LIT-5145

Pre-Submission checklist

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays 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

Live proxy against real AWS bedrock-runtime us-east-1, real Anthropic, and real OpenAI. Real spend, no mocks, no stubs, no recorded fixtures. git status --porcelain --untracked-files=no was empty in both worktrees, so no source was touched on either side. Same config, same script, same order, same proxy boot environment on both legs.

  • BEFORE: a66a10b1b5db1627cf8eef5a789d626136f3adbe, the merge base of this branch and litellm_internal_staging
  • AFTER: 58c4fa6ae9839736c458127b982c82c82a85f04f, the current tip

The merge base is the right BEFORE because git diff a66a10b1b5 58c4fa6ae9 -- litellm/ is exactly and only this PR's six source files. The two legs therefore differ by this PR alone, with none of the staging churn from the merge commit confounding the comparison.

Config used by both legs:

litellm_settings:
  return_response_headers: true
model_list:
  - model_name: bedrock-converse-haiku
    litellm_params: {model: bedrock/converse/us.anthropic.claude-haiku-4-5-20251001-v1:0}
  - model_name: bedrock-invoke-haiku
    litellm_params: {model: bedrock/invoke/us.anthropic.claude-haiku-4-5-20251001-v1:0}
  - model_name: bedrock-invoke-nova
    litellm_params: {model: bedrock/invoke/us.amazon.nova-lite-v1:0}
  - model_name: bedrock-invoke-badmodel      # error-parity probe
    litellm_params: {model: bedrock/invoke/does-not-exist-v1:0}
  - model_name: anthropic-haiku              # control, already worked before the PR
    litellm_params: {model: anthropic/claude-haiku-4-5-20251001}
  - model_name: generic-handler-openai       # the shared llm_http_handler path
    litellm_params: {model: hosted_vllm/gpt-4o-mini, api_base: https://api.openai.com/v1}

Command, run identically against each proxy:

curl -s -D - -o /dev/null -X POST "http://127.0.0.1:$PORT/v1/chat/completions" \
  -H "Authorization: Bearer $LITELLM_KEY" -H 'Content-Type: application/json' \
  -d '{"model":"bedrock-converse-haiku","messages":[{"role":"user","content":"hi"}],"max_tokens":8}' \
  | grep -iE '^(llm_provider-|x-litellm-)'

1. Headline symptom: llm_provider-x-amzn-requestid on /v1/chat/completions

== [BEFORE a66a10b1b5] bedrock-converse-haiku  stream=false -> HTTP 200
    (NONE)

== [BEFORE a66a10b1b5] bedrock-converse-haiku  stream=true  -> HTTP 200
    (NONE)

== [BEFORE a66a10b1b5] bedrock-invoke-haiku    stream=true  -> HTTP 200
    (NONE)

== [BEFORE a66a10b1b5] generic-handler-openai  stream=true  -> HTTP 200
    (NONE)
== [AFTER 58c4fa6ae9] bedrock-converse-haiku  stream=false -> HTTP 200
    x-litellm-model-name: bedrock/converse/us.anthropic.claude-haiku-4-5-20251001-v1:0
    llm_provider-date: Fri, 21 Aug 2026 03:28:38 GMT
    llm_provider-content-type: application/json
    llm_provider-content-length: 328
    llm_provider-connection: keep-alive
    llm_provider-x-amzn-requestid: ca22ae2a-3f07-46c5-b3b4-af49a6c5989f
    x-litellm-model-group: bedrock-converse-haiku

== [AFTER 58c4fa6ae9] bedrock-converse-haiku  stream=true  -> HTTP 200
    x-litellm-model-name: bedrock/converse/us.anthropic.claude-haiku-4-5-20251001-v1:0
    llm_provider-date: Fri, 21 Aug 2026 03:28:39 GMT
    llm_provider-content-type: application/vnd.amazon.eventstream
    llm_provider-transfer-encoding: chunked
    llm_provider-connection: keep-alive
    llm_provider-x-amzn-requestid: 6389965c-1030-43fb-b01e-159807da06f0
    x-litellm-model-group: bedrock-converse-haiku

== [AFTER 58c4fa6ae9] bedrock-invoke-haiku    stream=true  -> HTTP 200
    x-litellm-model-name: bedrock/invoke/us.anthropic.claude-haiku-4-5-20251001-v1:0
    llm_provider-date: Fri, 21 Aug 2026 03:28:41 GMT
    llm_provider-content-type: application/vnd.amazon.eventstream
    llm_provider-transfer-encoding: chunked
    llm_provider-connection: keep-alive
    llm_provider-x-amzn-requestid: c540c626-5d4d-4509-a019-027b3270be94
    llm_provider-x-amzn-bedrock-content-type: application/json
    x-litellm-model-group: bedrock-invoke-haiku

Control at the BEFORE commit, so every (NONE) above is a real absence rather than a broken harness:

== [BEFORE a66a10b1b5] anthropic-haiku  stream=false -> HTTP 200
    llm_provider-date: Fri, 21 Aug 2026 03:24:59 GMT
    llm_provider-anthropic-ratelimit-requests-limit: 10000
    llm_provider-anthropic-ratelimit-requests-remaining: 9999
    ... 32 llm_provider-* headers total

2. Full grid, llm_provider-* header count per cell

Every cell returned HTTP 200 on both legs. 26 cells per leg.

Endpoint Model stream=false stream=true
chat/completions bedrock-converse-haiku 0 → 5 0 → 5
chat/completions bedrock-invoke-haiku 10 → 10 0 → 6
chat/completions bedrock-invoke-nova 0 → 0 0 → 6
chat/completions anthropic-haiku 32 → 32 33 → 33
chat/completions generic-handler-openai 25 → 25 0 → 24
v1/messages bedrock-converse-haiku 0 → 0 0 → 0
v1/messages bedrock-invoke-haiku 0 → 0 6 → 6
v1/messages bedrock-invoke-nova 0 → 0 0 → 0
v1/messages anthropic-haiku 0 → 0 29 → 29
v1/responses bedrock-converse-haiku 0 → 5 0 → 0
v1/responses bedrock-invoke-haiku 10 → 10 0 → 0
v1/responses bedrock-invoke-nova 0 → 0 0 → 0
v1/responses anthropic-haiku 32 → 32 0 → 0

Six cells gained headers. No cell went the other way: nothing that returned headers before returns fewer after.

3. The generic handler path (~30 providers share it)

generic-handler-openai streaming went from zero headers to 24, matching what its own non-streaming path already returned: date, content-type, transfer-encoding, connection, cf-ray, cf-cache-status, server, strict-transport-security, x-content-type-options, access-control-expose-headers, openai-organization, openai-processing-ms, openai-project, openai-version, x-openai-proxy-wasm, x-ratelimit-limit-requests, x-ratelimit-limit-tokens, x-ratelimit-remaining-requests, x-ratelimit-remaining-tokens, x-ratelimit-reset-requests, x-ratelimit-reset-tokens, x-request-id, set-cookie, alt-svc.

4. No clobber of x-litellm-*

set_provider_response_headers assigns _hidden_params["additional_headers"] rather than merging into it, so the full response header set was dumped on every model in both stream modes and compared key for key against the BEFORE leg.

Every x-litellm-* header survives on every cell: call-id, model-id, model-group, model-name, model-api-base, version, key-spend, attempted-retries, attempted-fallbacks, response-duration-ms, overhead-duration-ms, callback-duration-ms, and the seven response-cost-* members. x-litellm-model-group is written by router.py into that same dict and is present on both converse cells, which is direct live evidence for the writer that shares the dict most directly.

This holds by construction as well: set_provider_response_headers runs in the innermost handler on a freshly built ModelResponse, and every other writer of that dict runs strictly later and merges via setdefault(...).update(...). Two writers were not reachable on this rig and are noted under Caveats.

Two absences that are baselines rather than regressions, identical on both legs: bare x-litellm-response-cost is absent on every streaming cell (only the -original/-input/-output breakdown is emitted), and x-litellm-timeout is absent except on error responses.

5. Sensitive-header audit, run at both commits

Header generic-openai ns generic-openai stream anthropic ns anthropic stream
llm_provider-authorization absent absent absent absent
llm_provider-set-cookie present 0 → present absent absent
llm_provider-openai-organization present 0 → present absent absent
llm_provider-openai-project present 0 → present absent absent
llm_provider-cf-ray present 0 → present present present
llm_provider-anthropic-organization-id absent absent present present
total llm_provider-* 25 → 25 0 → 24 32 → 32 33 → 33

Non-streaming already returned this set before the PR. Streaming was clean only because it forwarded nothing at all, so the PR widens an existing forwarding behavior to streaming rather than creating one, and authorization is absent on both legs. Called out under Caveats.

6. Abandoned streams, the eager-construction risk

Invoke streaming now issues the upstream request eagerly instead of deferring it to a make_call partial, so the case to check is a client that opens a stream and walks away. Eight streaming requests to bedrock-invoke-haiku were hung up at 0.35s (curl exit 28 on each), at both commits, twice per leg.

The proxy stayed healthy every time: /health/liveliness 200, /health/readiness 200, the next non-streaming request 200 with all 10 provider headers, and the next streaming request 200 with 5 chunks and its own llm_provider-x-amzn-requestid. No hang, no degradation, no file-descriptor symptom.

7. Error parity

bedrock-invoke-badmodel returns HTTP 400 in all four combinations, with zero llm_provider-* headers. Non-streaming is byte-identical across the two legs. Streaming is not, and this is the one user-visible change the PR makes beyond headers:

BEFORE stream=false: {"error":{"message":"litellm.BadRequestError: BedrockException - {...}. Received Model Group=bedrock-invoke-badmodel
Available Model Group Fallbacks=None","type":null,"param":null,"code":"400"}}

BEFORE stream=true:  {"error":{"message":"{...}. Received Model Group=bedrock-invoke-badmodel
Available Model Group Fallbacks=None","type":"None","param":"None","code":"400"}}

AFTER  both modes:   identical to the BEFORE stream=false form

Three differences on the invoke streaming error path: the message gains the litellm.BadRequestError: BedrockException - prefix, type and param go from the JSON string "None" to real JSON null, and x-litellm-timeout now appears where it was absent. Eager construction makes the error raise from the same place the non-streaming path raises it, so it picks up the normal exception mapping. Streaming errors now match non-streaming errors, which is the better shape, but it is a response-body change and is called out under Caveats. The status stays 400 in all four cases, so nothing turned into a 500 or a hang.

8. Unit tests and mutation check

At the tip, the four test files this PR touches:

$ pytest tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py \
         tests/test_litellm/llms/chat/test_converse_handler.py \
         tests/test_litellm/llms/custom_httpx/test_llm_http_handler.py \
         tests/llm_translation/test_bedrock_moonshot.py -q -p no:randomly
113 passed, 29 skipped, 8 warnings in 2.50s

Mutation check, reverting only the six source files to the merge base and rerunning the identical command:

$ git checkout a66a10b1b5 -- litellm/litellm_core_utils/streaming_handler.py \
    litellm/llms/bedrock/chat/converse_handler.py \
    litellm/llms/bedrock/chat/invoke_handler.py \
    litellm/llms/bedrock/chat/invoke_transformations/base_invoke_transformation.py \
    litellm/llms/custom_httpx/llm_http_handler.py litellm/types/utils.py

FAILED tests/test_litellm/llms/chat/test_converse_handler.py::test_converse_completion_forwards_bedrock_response_headers
FAILED tests/test_litellm/llms/chat/test_converse_handler.py::test_async_converse_completion_forwards_bedrock_response_headers
FAILED tests/test_litellm/llms/chat/test_converse_handler.py::test_converse_streaming_forwards_bedrock_response_headers
FAILED tests/test_litellm/llms/chat/test_converse_handler.py::test_async_converse_streaming_forwards_bedrock_response_headers
FAILED tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py::test_invoke_streaming_forwards_bedrock_response_headers
FAILED tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py::test_async_invoke_streaming_forwards_bedrock_response_headers
FAILED tests/test_litellm/llms/custom_httpx/test_llm_http_handler.py::test_generic_http_handler_sync_streaming_forwards_provider_response_headers
FAILED tests/test_litellm/llms/custom_httpx/test_llm_http_handler.py::test_generic_http_handler_async_streaming_forwards_provider_response_headers
FAILED tests/llm_translation/test_bedrock_moonshot.py::TestBedrockMoonshotInvoke::test_streaming
9 failed, 104 passed, 29 skipped in 2.62s

Nine tests die without the fix, one for each changed path: converse sync and async in both stream modes, invoke sync and async streaming, generic-handler sync and async streaming, and moonshot invoke streaming. These are real regression tests, not tests that pass either way.

make check passes at the tip.

9. Gaps that are not regressions

Identical on both legs, so this PR does not reach them and does not cause them:

  • /v1/responses streaming returns zero provider headers for every provider
  • converse on /v1/messages returns zero provider headers in both modes
  • bedrock/invoke Nova returns zero provider headers when not streaming

Type

🐛 Bug Fix

Caveats (if any)

  • Invoke streaming now builds its stream eagerly, not lazily. base_invoke_transformation.py used to hand CustomStreamWrapper a make_call partial; it now issues the upstream request first so the headers exist before the first chunk. A caller that builds the stream and never iterates it holds that connection until something closes it, and CustomStreamWrapper.__del__ does not close completion_stream (there is no sync close(), only aclose()). The proxy is unaffected because it calls aclose() on the generator in common_request_processing.py, so the exposure is direct sync SDK callers only. Converse and the generic HTTP handler already worked this way before the PR.
  • Bedrock invoke streaming error bodies change shape. Because the stream is now opened eagerly, an upstream error raises from the same place the non-streaming path raises it and picks up the normal exception mapping. On bedrock/invoke streaming the 400 body gains the litellm.BadRequestError: BedrockException - message prefix, error.type and error.param go from the JSON string "None" to real JSON null, and an x-litellm-timeout response header appears. The status code is unchanged and the new shape matches what non-streaming has always returned, so this is an alignment rather than a break, but a client matching on error.type == "None" or on the unprefixed message will stop matching with no error.
  • The forwarded headers have no denylist. _get_llm_provider_headers re-emits every upstream header verbatim as llm_provider-*, so the streaming path now returns the same set-cookie (__cf_bm), openai-organization, openai-project, and cf-ray values that the non-streaming path already returned before this PR. authorization is not among them. This is a pre-existing leak that the PR widens from non-streaming to streaming; narrowing it needs its own change to get_headers.py.
  • This is not behind return_response_headers. That flag only switches the OpenAI and Azure SDK paths to with_raw_response; the Bedrock and generic httpx handlers forward unconditionally, and the proxy splats additional_headers with no gate. So every deployment on these providers starts seeing the new headers on upgrade.
  • set_provider_response_headers assigns _hidden_params["additional_headers"] instead of merging into it. That is safe here because it runs in the innermost handler on a freshly built ModelResponse, before any other writer of that dict exists, and every later writer merges with setdefault(...).update(...). The live run confirms it for router.py (x-litellm-model-group survives on both converse cells). Two writers could not be exercised on the QA rig, parallel_request_limiter.py:837 and dynamic_rate_limiter_v3.py:667, because both need key-level rpm/tpm limits, virtual keys, and a database; for that pair the claim rests on the ordering argument rather than on evidence. Anyone adding a writer that runs before the LLM handler returns would need to merge rather than assign.
  • Gaps this PR does not close (identical before and after, so not regressions): /v1/responses streaming returns no provider headers for any provider, converse on /v1/messages returns none in either mode, and bedrock/invoke Nova returns none when not streaming.

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

Link to Devin session: https://app.devin.ai/sessions/698b5dfc69ee439e810c80a77a5e35d7


Note

Medium Risk
Touches Bedrock converse/invoke and the shared HTTP streaming path, and makes invoke streaming eager. Header plumbing is not auth-critical but can affect stream lifecycle and what is exposed to clients.

Overview
Surfaces upstream provider response headers (e.g. Bedrock x-amzn-requestid) on /chat/completions so they can be returned as llm_provider-* headers for debugging and AWS correlation.

Converse now copies response.headers onto non-streaming ModelResponse via set_provider_response_headers, and streaming wrappers receive those headers from make_sync_call / make_call.

Invoke streaming no longer defers the HTTP call through a make_call partial. The stream is opened immediately so headers exist when CustomStreamWrapper is built. The generic HTTP handler streaming path also passes _response_headers through.

Caveat: invoke streaming is now eager rather than lazy.

Reviewed by Cursor Bugbot for commit 58c4fa6. Bugbot is set up for automated code reviews on this repo. Configure here.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@CLAassistant

CLAassistant commented Aug 15, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ mateo-berri
❌ devin-ai-integration[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR forwards upstream provider response headers through Bedrock Converse, Bedrock Invoke, and generic HTTP streaming completion paths.

  • Attaches response headers to non-streaming model responses and streaming wrappers.
  • Creates Bedrock Invoke streams eagerly so headers are available before the response body begins.
  • Adds regression coverage for synchronous and asynchronous header forwarding.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
litellm/llms/bedrock/chat/converse_handler.py Propagates Converse response headers through synchronous, asynchronous, streaming, and non-streaming responses.
litellm/llms/bedrock/chat/invoke_handler.py Returns provider headers alongside decoded Invoke completion streams.
litellm/llms/bedrock/chat/invoke_transformations/base_invoke_transformation.py Eagerly constructs Invoke streams and supplies their upstream headers to CustomStreamWrapper.
litellm/llms/custom_httpx/llm_http_handler.py Passes generic HTTP provider response headers into streaming wrappers.
litellm/types/utils.py Adds a shared model-response helper for processing and storing provider response headers.

Reviews (3): Last reviewed commit: "chore: merge litellm_internal_staging in..." | Re-trigger Greptile

Comment thread tests/llm_translation/test_bedrock_moonshot.py
@codecov

codecov Bot commented Aug 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.00000% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/llms/bedrock/chat/converse_handler.py 90.90% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@codspeed-hq

codspeed-hq Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_forward_bedrock_response_headers (58c4fa6) with litellm_internal_staging (65b4ac0)1

Open in CodSpeed

Footnotes

  1. No successful run was found on litellm_internal_staging (58c4fa6) during the generation of this report, so eb6296e was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Add sync and async regression tests for the BaseLLMHTTPHandler streaming
path, which forwards provider response headers for the ~30 providers that
ride the generic handler and had no coverage. Also drop redundant setup
prose from the moonshot invoke test docstring.
@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

…sponse_headers

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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 722c650. Configure here.

@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

Comment thread litellm/types/utils.py
@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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 58c4fa6. Configure here.

@mateo-berri mateo-berri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mateo-berri
mateo-berri merged commit 4b29702 into litellm_internal_staging Aug 21, 2026
74 checks passed
@mateo-berri
mateo-berri deleted the litellm_forward_bedrock_response_headers branch August 21, 2026 03:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants