From 5ce81631fed86bb8e208c0bc4f9f6f49cc97707a Mon Sep 17 00:00:00 2001 From: Koh Jun Hao <46019297+kohjunhao@users.noreply.github.com> Date: Sat, 3 Oct 2026 12:12:33 +0800 Subject: [PATCH] fix(bedrock): send the anthropic-workspace-id header to Bedrock Mantle (#44173) aws_bedrock_project_id reached Bedrock Mantle as anthropic-workspace, a header AWS ignores, so requests ran under account defaults and models that require a project data-retention mode failed with a 400. Send the header AWS documents, anthropic-workspace-id, on both Mantle routes. Re-lands #31994 by @gunjanjaswal, merged into the since-deleted litellm_oss_staging branch on 2026-08-22, which never reached main. Fixes #31947 Co-authored-by: Claude Fable 5.1 --- .../llms/bedrock/chat/mantle/transformation.py | 2 +- .../bedrock/messages/mantle_transformation.py | 2 +- tests/unit/llms/bedrock/test_mantle.py | 16 ++++++++++------ ...est_bedrock_mantle_messages_transformation.py | 3 ++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/litellm/llms/bedrock/chat/mantle/transformation.py b/litellm/llms/bedrock/chat/mantle/transformation.py index 7e2037c33f1..583fcb6b230 100644 --- a/litellm/llms/bedrock/chat/mantle/transformation.py +++ b/litellm/llms/bedrock/chat/mantle/transformation.py @@ -73,7 +73,7 @@ class AmazonMantleConfig(AmazonAnthropicClaudeConfig): ) project_id: Final = litellm_params.get("aws_bedrock_project_id") if project_id: - headers["anthropic-workspace"] = project_id + headers["anthropic-workspace-id"] = project_id return headers def transform_request( diff --git a/litellm/llms/bedrock/messages/mantle_transformation.py b/litellm/llms/bedrock/messages/mantle_transformation.py index ae4e9de3511..0ee5dcbe557 100644 --- a/litellm/llms/bedrock/messages/mantle_transformation.py +++ b/litellm/llms/bedrock/messages/mantle_transformation.py @@ -104,7 +104,7 @@ class AmazonMantleMessagesConfig(AmazonAnthropicClaudeMessagesConfig): { name: value for name, value in ( - ("anthropic-workspace", project_id), + ("anthropic-workspace-id", project_id), ("anthropic-version", None if has_version else DEFAULT_ANTHROPIC_API_VERSION), ) if value diff --git a/tests/unit/llms/bedrock/test_mantle.py b/tests/unit/llms/bedrock/test_mantle.py index 37cf49a85ec..63af0105f5b 100644 --- a/tests/unit/llms/bedrock/test_mantle.py +++ b/tests/unit/llms/bedrock/test_mantle.py @@ -18,6 +18,10 @@ from litellm.llms.bedrock.messages.mantle_transformation import ( AmazonMantleMessagesConfig, ) +# AWS names this header for Mantle workspaces on the Anthropic Messages API, checked 2026-10-02: +# https://docs.aws.amazon.com/bedrock/latest/userguide/workspaces.html +_MANTLE_WORKSPACE_HEADER = "anthropic-workspace-id" + def _anthropic_response(url: str) -> httpx.Response: return httpx.Response( @@ -345,7 +349,7 @@ def test_mantle_validate_environment_sets_workspace_header(): optional_params={}, litellm_params={"aws_bedrock_project_id": "proj_abc123def456"}, ) - assert headers["anthropic-workspace"] == "proj_abc123def456" + assert headers[_MANTLE_WORKSPACE_HEADER] == "proj_abc123def456" def test_mantle_validate_environment_without_project_id(): @@ -357,7 +361,7 @@ def test_mantle_validate_environment_without_project_id(): optional_params={}, litellm_params={"aws_bedrock_project_id": None}, ) - assert "anthropic-workspace" not in headers + assert _MANTLE_WORKSPACE_HEADER not in headers def test_mantle_messages_validate_environment_sets_workspace_header(): @@ -370,7 +374,7 @@ def test_mantle_messages_validate_environment_sets_workspace_header(): litellm_params={"aws_bedrock_project_id": "proj_abc123def456"}, api_base="https://bedrock-mantle.us-east-1.api.aws/anthropic/v1/messages", ) - assert headers["anthropic-workspace"] == "proj_abc123def456" + assert headers[_MANTLE_WORKSPACE_HEADER] == "proj_abc123def456" assert api_base == "https://bedrock-mantle.us-east-1.api.aws/anthropic/v1/messages" @@ -383,7 +387,7 @@ def test_mantle_messages_validate_environment_without_project_id(): optional_params={}, litellm_params={}, ) - assert "anthropic-workspace" not in headers + assert _MANTLE_WORKSPACE_HEADER not in headers def test_mantle_completion_sends_workspace_header_and_clean_body(): @@ -409,7 +413,7 @@ def test_mantle_completion_sends_workspace_header_and_clean_body(): assert response.choices[0].message.content == "ok" assert len(requests) == 1 assert requests[0]["path"] == "/anthropic/v1/messages" - assert requests[0]["headers"]["anthropic-workspace"] == "proj_abc123def456" + assert requests[0]["headers"][_MANTLE_WORKSPACE_HEADER] == "proj_abc123def456" assert "aws_bedrock_project_id" not in requests[0]["body"] @@ -443,7 +447,7 @@ async def test_mantle_anthropic_messages_sends_workspace_header_and_clean_body() assert response["content"][0]["text"] == "ok" assert len(requests) == 1 assert requests[0]["path"] == "/anthropic/v1/messages" - assert requests[0]["headers"]["anthropic-workspace"] == "proj_abc123def456" + assert requests[0]["headers"][_MANTLE_WORKSPACE_HEADER] == "proj_abc123def456" assert "aws_bedrock_project_id" not in requests[0]["body"] diff --git a/tests/unit/llms/bedrock_mantle/test_bedrock_mantle_messages_transformation.py b/tests/unit/llms/bedrock_mantle/test_bedrock_mantle_messages_transformation.py index 5f69b36c87a..923572c4f46 100644 --- a/tests/unit/llms/bedrock_mantle/test_bedrock_mantle_messages_transformation.py +++ b/tests/unit/llms/bedrock_mantle/test_bedrock_mantle_messages_transformation.py @@ -193,7 +193,8 @@ class TestEnvironment: assert "anthropic-version" not in merged def test_project_id_becomes_the_workspace_header(self): - assert self._validate({}, {"aws_bedrock_project_id": "proj_123"})["anthropic-workspace"] == "proj_123" + # header name from https://docs.aws.amazon.com/bedrock/latest/userguide/workspaces.html, checked 2026-10-02 + assert self._validate({}, {"aws_bedrock_project_id": "proj_123"})["anthropic-workspace-id"] == "proj_123" class TestRequestBody: