diff --git a/litellm/llms/anthropic/wif.py b/litellm/llms/anthropic/wif.py index 6b88bfd7f63..f490ad4938f 100644 --- a/litellm/llms/anthropic/wif.py +++ b/litellm/llms/anthropic/wif.py @@ -141,7 +141,9 @@ def _resolve_identity_source( if source_kind is None: legacy_ref: Final = _resolve_assertion_ref(litellm_params) return (legacy_ref, None) if legacy_ref is not None else None - params: Final = litellm_params if litellm_params is not None else _EMPTY_PARAMS + params: Final[Mapping[str, object]] = MappingProxyType( + {key: value for key, value in (litellm_params or _EMPTY_PARAMS).items() if value is not None} + ) match source_kind: case AnthropicIdentitySourceKind.internal_issuer.value: _reject_foreign_variant_fields(params, foreign_field_map=_KEYCLOAK_FIELD_MAP, chosen_kind=source_kind) diff --git a/tests/test_litellm/llms/anthropic/test_anthropic_wif.py b/tests/test_litellm/llms/anthropic/test_anthropic_wif.py index 12b11dbc95f..db9fc50c09f 100644 --- a/tests/test_litellm/llms/anthropic/test_anthropic_wif.py +++ b/tests/test_litellm/llms/anthropic/test_anthropic_wif.py @@ -25,6 +25,7 @@ from litellm.llms.base_llm.auth.identity_source import ( ) from litellm.llms.base_llm.auth.jwt_signing import build_jwks, rfc7638_thumbprint from litellm.llms.base_llm.auth.token_exchange import JwtBearerTokenExchangeEngine +from litellm.types.router import GenericLiteLLMParams from litellm.llms.base_llm.auth.types import ( AssertionSourceError, ExchangeError, @@ -930,6 +931,23 @@ class TestKeycloakIdentitySourceDispatch: assert first.assertion_ref != second.assertion_ref + +@pytest.mark.parametrize( + "sparse_params", + [TestInternalIssuerIdentitySourceDispatch.LITELLM_PARAMS, TestKeycloakIdentitySourceDispatch.LITELLM_PARAMS], + ids=["internal_issuer", "keycloak"], +) +def test_dense_router_params_dump_resolves_like_the_sparse_config(sparse_params: Mapping[str, object]): + dense_params = dict(GenericLiteLLMParams(**sparse_params)) + assert any(value is None for value in dense_params.values()) + + dense = resolve_anthropic_wif_params(dense_params) + sparse = resolve_anthropic_wif_params(sparse_params) + + assert dense is not None and sparse is not None + assert dense.assertion_ref == sparse.assertion_ref + + class TestIdentitySourceValidationFailsClosed: """Unknown discriminator, a missing required variant field, and a field belonging to the other variant are all hard config errors at resolution time -- never a silent fallback to