litellm - ✅(Solved) Fix aws_role_name in proxy config YAML silently dropped — cross-account Bedrock AssumeRole never fires [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#25884Fetched 2026-04-17 08:28:19
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
labeled ×1

When configuring aws_role_name in litellm_params via the proxy config YAML for cross-account Bedrock access, the parameter is silently dropped during optional params processing. The STS AssumeRole call never fires, and Bedrock calls land in the host account's IAM identity instead of the target role's account.

Error Message

Actual behavior: AssumeRole never fires. Bedrock is called with the ECS task role's own credentials (central account), which doesn't have Bedrock model access enabled. Error: "Model use case details have not been submitted."

Root Cause

Root Cause (traced through source code)

Fix Action

Fix / Workaround

for k, v in special_params.items():
    if k.startswith("aws_") and (
        custom_llm_provider != "bedrock"  # Correctly NOT skipped for bedrock
        ...
    ):
        continue
    passed_params[k] = v  # aws_role_name merged into passed_params ✅

PR fix notes

PR #25982: fix(bedrock): fall back to litellm_params for aws_role_name and related credential fields

Description (problem / solution / changelog)

Summary

Fixes #25884.

AWS credential fields declared under litellm_params in proxy config YAML (e.g. aws_role_name for cross-account Bedrock via STS AssumeRole) never reach the Converse handler today. They are correctly merged into passed_params inside base_pre_process_non_default_params, but the subsequent comprehension only keeps keys present in DEFAULT_CHAT_COMPLETION_PARAM_VALUES — which contains only canonical OpenAI chat-completion params, not any aws_* field.

As a result, optional_params["aws_role_name"] was always None in the handler and Bedrock was invoked with the ambient ECS / EC2 task-role identity, silently breaking per-model cross-account routing.

Fix

The handler already receives litellm_params, and the field is stored there by get_litellm_params via _OPTIONAL_KWARGS_KEYS. Fall back to that dict when a given aws_* field is absent from optional_params, so request-level overrides still win but deployment-level config keeps working.

Applies to: aws_role_name, aws_session_name, aws_profile_name, aws_web_identity_token, aws_sts_endpoint, aws_external_id, aws_access_key_id, aws_secret_access_key, aws_session_token, aws_bedrock_runtime_endpoint.

This matches the reporter's Option A in #25884.

Test plan

  • New unit test test_converse_handler_reads_aws_credentials_from_litellm_params — verifies all 9 AWS credential fields round-trip through litellm_params when optional_params is empty (reproducer for the bug).
  • New unit test test_converse_handler_optional_params_win_over_litellm_params — verifies request-level values in optional_params still take precedence over deployment-level values in litellm_params.
  • Existing test_converse_handler_external_id_extraction still passes (unchanged path where only optional_params is populated).

Changed files

  • litellm/llms/bedrock/chat/converse_handler.py (modified, +36/-12)
  • tests/test_litellm/llms/bedrock/test_base_aws_llm.py (modified, +141/-0)

Code Example

model_list:
  - model_name: claude-sonnet-4-6
    litellm_params:
      model: bedrock/us.anthropic.claude-sonnet-4-6
      aws_region_name: us-west-2
      aws_role_name: arn:aws:iam::244910800867:role/LiteLLMBedrockAccess
      aws_session_name: litellm-dept-a
    model_info:
      tags:
        - dept-a
  - model_name: claude-sonnet-4-6
    litellm_params:
      model: bedrock/us.anthropic.claude-sonnet-4-6
      aws_region_name: us-west-2
      aws_role_name: arn:aws:iam::987654321012:role/LiteLLMBedrockAccess
      aws_session_name: litellm-dept-b
    model_info:
      tags:
        - dept-b

litellm_settings:
  enable_tag_filtering: true
  drop_params: true

---

passed_params = locals().copy()
special_params = passed_params.pop("kwargs")  # aws_role_name is here

---

for k, v in special_params.items():
    if k.startswith("aws_") and (
        custom_llm_provider != "bedrock"  # Correctly NOT skipped for bedrock
        ...
    ):
        continue
    passed_params[k] = v  # aws_role_name merged into passed_params ✅

---

non_default_params = {
    k: v
    for k, v in passed_params.items()
    if (
        ...
        and k in default_param_values   # ← DEFAULT_CHAT_COMPLETION_PARAM_VALUES
        and v != default_param_values[k]
        ...
    )
}

---

aws_role_name = optional_params.pop("aws_role_name", None)  # Returns None

---

# config.yaml
model_list:
  - model_name: test-model
    litellm_params:
      model: bedrock/us.anthropic.claude-sonnet-4-6
      aws_region_name: us-west-2
      aws_role_name: arn:aws:iam::TARGET_ACCOUNT:role/SomeRole
      aws_session_name: litellm-test

litellm_settings:
  drop_params: true

---

litellm --config config.yaml --detailed_debug
# Send a chat completion request
# Observe: no STS AssumeRole call in logs, Bedrock called with host credentials

---

aws_role_name = optional_params.pop("aws_role_name", None) or litellm_params.get("aws_role_name")
aws_session_name = optional_params.pop("aws_session_name", None) or litellm_params.get("aws_session_name")
# ... same for other aws_ params
RAW_BUFFERClick to expand / collapse

Bug Report: aws_role_name in proxy config YAML silently ignored — cross-account Bedrock AssumeRole never fires

Summary

When configuring aws_role_name in litellm_params via the proxy config YAML for cross-account Bedrock access, the parameter is silently dropped during optional params processing. The STS AssumeRole call never fires, and Bedrock calls land in the host account's IAM identity instead of the target role's account.

Use Case

We're a government organization (City and County of San Francisco) deploying LiteLLM as a centralized LLM Gateway on ECS Fargate. We have a central platform account running LiteLLM and multiple department accounts with Bedrock model access enabled. Each department has its own AWS account with a LiteLLMBedrockAccess IAM role that the LiteLLM ECS task role can assume.

Our config uses tag-based routing so each department's models route to their own Bedrock account for billing isolation:

model_list:
  - model_name: claude-sonnet-4-6
    litellm_params:
      model: bedrock/us.anthropic.claude-sonnet-4-6
      aws_region_name: us-west-2
      aws_role_name: arn:aws:iam::244910800867:role/LiteLLMBedrockAccess
      aws_session_name: litellm-dept-a
    model_info:
      tags:
        - dept-a
  - model_name: claude-sonnet-4-6
    litellm_params:
      model: bedrock/us.anthropic.claude-sonnet-4-6
      aws_region_name: us-west-2
      aws_role_name: arn:aws:iam::987654321012:role/LiteLLMBedrockAccess
      aws_session_name: litellm-dept-b
    model_info:
      tags:
        - dept-b

litellm_settings:
  enable_tag_filtering: true
  drop_params: true

This config format matches the LiteLLM documentation at https://docs.litellm.ai/docs/providers/bedrock (cross-account section).

Expected behavior: LiteLLM task role calls STS AssumeRole into the department role, then invokes Bedrock with the assumed credentials.

Actual behavior: AssumeRole never fires. Bedrock is called with the ECS task role's own credentials (central account), which doesn't have Bedrock model access enabled. Error: "Model use case details have not been submitted."

Root Cause (traced through source code)

The parameter flows correctly through the router but gets dropped inside get_optional_params() before reaching the Bedrock handler. Here is the exact code path:

1. Router passes aws_role_name correctly

litellm/router.py — The router spreads litellm_params from the deployment config into litellm.completion(**kwargs). At this point, aws_role_name is a top-level kwarg. ✅

2. completion() includes it in non-default params

litellm/main.pyget_non_default_completion_params(kwargs) returns aws_role_name because it is not in all_litellm_params or OPENAI_CHAT_COMPLETION_PARAMS. ✅

3. get_optional_params() receives it via **kwargs

litellm/utils.py:3934aws_role_name lands in **kwargs (the catch-all). Then:

passed_params = locals().copy()
special_params = passed_params.pop("kwargs")  # aws_role_name is here

4. base_pre_process_non_default_params() merges it, then filters it out

litellm/utils.py:3688-3723

Line 3688-3702: aws_role_name is correctly merged from special_params into passed_params (the aws_ prefix check correctly allows it for bedrock):

for k, v in special_params.items():
    if k.startswith("aws_") and (
        custom_llm_provider != "bedrock"  # Correctly NOT skipped for bedrock
        ...
    ):
        continue
    passed_params[k] = v  # aws_role_name merged into passed_params ✅

Line 3705-3723 — THE BUG: The comprehension that builds non_default_params requires k in default_param_values:

non_default_params = {
    k: v
    for k, v in passed_params.items()
    if (
        ...
        and k in default_param_values   # ← DEFAULT_CHAT_COMPLETION_PARAM_VALUES
        and v != default_param_values[k]
        ...
    )
}

DEFAULT_CHAT_COMPLETION_PARAM_VALUES (litellm/constants.py:668) contains only OpenAI chat completion params (temperature, top_p, tools, etc.). aws_role_name is not in this dict, so it is filtered out. ❌

5. map_special_auth_params() doesn't help

litellm/utils.py:3851-3856litellm/llms/bedrock/common_utils.py:77-88

map_special_auth_params() only maps region_nameaws_region_name. It does not handle aws_role_name, aws_session_name, or any other AWS credential params. ❌

6. Handler gets None

litellm/llms/bedrock/chat/converse_handler.py:324:

aws_role_name = optional_params.pop("aws_role_name", None)  # Returns None

get_credentials() is called with aws_role_name=None → no AssumeRole → ambient credentials used. ❌

Meanwhile, litellm_params has it

litellm/litellm_core_utils/get_litellm_params.py:160-162 correctly stores aws_role_name in litellm_params via _OPTIONAL_KWARGS_KEYS. The handler receives litellm_params as a parameter, but reads aws_role_name from optional_params instead. Nobody transfers it.

Reproduction

# config.yaml
model_list:
  - model_name: test-model
    litellm_params:
      model: bedrock/us.anthropic.claude-sonnet-4-6
      aws_region_name: us-west-2
      aws_role_name: arn:aws:iam::TARGET_ACCOUNT:role/SomeRole
      aws_session_name: litellm-test

litellm_settings:
  drop_params: true
litellm --config config.yaml --detailed_debug
# Send a chat completion request
# Observe: no STS AssumeRole call in logs, Bedrock called with host credentials

Suggested Fix

Option A (minimal): In converse_handler.py:completion(), fall back to litellm_params when optional_params doesn't have AWS credential fields:

aws_role_name = optional_params.pop("aws_role_name", None) or litellm_params.get("aws_role_name")
aws_session_name = optional_params.pop("aws_session_name", None) or litellm_params.get("aws_session_name")
# ... same for other aws_ params

Option B (proper): Add aws_role_name, aws_session_name, aws_access_key_id, aws_secret_access_key, aws_session_token, aws_profile_name, aws_web_identity_token, aws_sts_endpoint, aws_external_id, and aws_bedrock_runtime_endpoint to DEFAULT_CHAT_COMPLETION_PARAM_VALUES in litellm/constants.py so they survive the filter in base_pre_process_non_default_params().

Option C: Expand map_special_auth_params() in bedrock/common_utils.py to copy all aws_* params from passed_params into optional_params, not just region_name.

Environment

  • LiteLLM version: main-v1.82.3-stable (also tested main-latest)
  • Deployment: ECS Fargate with task role that has sts:AssumeRole permission to target roles
  • IAM trust policies verified (direct aws sts assume-role works from the task role)
  • Direct Bedrock invocation from target account works

Impact

This blocks any proxy deployment that uses per-model cross-account Bedrock routing via aws_role_name in the config YAML. The parameter is documented, accepted by the config parser, and stored correctly in litellm_params, but never reaches the handler that needs it.

extent analysis

TL;DR

The aws_role_name parameter in the proxy config YAML is silently ignored due to a filtering issue in the base_pre_process_non_default_params() function, preventing the STS AssumeRole call from firing, and can be fixed by modifying the converse_handler.py to fall back to litellm_params or by adding the aws_role_name to the DEFAULT_CHAT_COMPLETION_PARAM_VALUES.

Guidance

  • Identify the root cause of the issue by tracing the code path from the router to the handler, focusing on how the aws_role_name parameter is processed and filtered.
  • Verify that the aws_role_name is correctly stored in litellm_params but not transferred to optional_params, causing the handler to use ambient credentials instead of the assumed role.
  • Consider implementing one of the suggested fixes:
    • Option A: Modify converse_handler.py to fall back to litellm_params when optional_params doesn't have AWS credential fields.
    • Option B: Add aws_role_name and other relevant AWS params to DEFAULT_CHAT_COMPLETION_PARAM_VALUES to prevent filtering.
    • Option C: Expand map_special_auth_params() to copy all aws_* params from passed_params into optional_params.

Example

# converse_handler.py:completion()
aws_role_name = optional_params.pop("aws_role_name", None) or litellm_params.get("aws_role_name")
aws_session_name = optional_params.pop("aws_session_name", None) or litellm_params.get("aws_session_name")

Notes

  • The issue is specific to the LiteLLM version main-v1.82.3-stable and may not affect other versions.
  • The suggested fixes may have implications for other parts of the codebase, and thorough testing is recommended to ensure no regressions are introduced.

Recommendation

Apply workaround: Modify converse_handler.py to fall back to litellm_params when optional_params doesn't have AWS credential fields, as this is the most straightforward and minimal fix.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

litellm - ✅(Solved) Fix aws_role_name in proxy config YAML silently dropped — cross-account Bedrock AssumeRole never fires [1 pull requests, 1 participants]