From bce6d2893f88eb6d3846ada21ff73dd840ea5ca8 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Wed, 28 Oct 2026 21:47:31 -0700 Subject: [PATCH] fix(router): validate strict litellm params through a helper so star imports cannot re-bind a public Final --- litellm/main.py | 6 ++---- litellm/router.py | 8 ++++---- litellm/types/router.py | 13 +++++++++++-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/litellm/main.py b/litellm/main.py index ec024eee433..44a595cbc43 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -154,7 +154,7 @@ from litellm.types.completion import ( ) from litellm.types.litellm_params import ControlOptions, RetryStrategy from litellm.types.llms.openai import AllMessageValues -from litellm.types.router import STRICT_LITELLM_PARAMS, GenericLiteLLMParams +from litellm.types.router import GenericLiteLLMParams, validate_litellm_params_strictly from litellm.types.utils import ( BaseUrlRoutingHint, CustomPricingLiteLLMParams, @@ -401,9 +401,7 @@ class _SupplementalProviderParams: def _supplemental_provider_params(kwargs: Mapping[str, object], model: str) -> _SupplementalProviderParams: supplemental: Final = {key: kwargs[key] for key in SUPPLEMENTAL_KWARGS_KEYS if key in kwargs} try: - return _SupplementalProviderParams( - params=GenericLiteLLMParams.model_validate(supplemental, context=STRICT_LITELLM_PARAMS) - ) + return _SupplementalProviderParams(params=validate_litellm_params_strictly(GenericLiteLLMParams, supplemental)) except ValidationError as error: invalid: Final = tuple(detail for detail in error.errors() if detail["loc"]) invalid_keys: Final = frozenset(str(detail["loc"][0]) for detail in invalid) diff --git a/litellm/router.py b/litellm/router.py index 2a614eaf086..3a5a4c1a6d9 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -414,7 +414,6 @@ from litellm.types.llms.openai import ( ) from litellm.types.router import ( CONFIGURABLE_CLIENTSIDE_AUTH_PARAMS, - STRICT_LITELLM_PARAMS, VALID_LITELLM_ENVIRONMENTS, AlertingConfig, AllowedFailsPolicy, @@ -451,6 +450,7 @@ from litellm.types.router import ( SearchToolTypedDict, TaggedPreRoutingStrategy, holds_secret_pointer, + validate_litellm_params_strictly, ) from litellm.types.services import ServiceTypes from litellm.types.utils import ( @@ -704,7 +704,7 @@ def _malformed_request_params_the_deployment_sets( if key in request and deployment_params.get(key) is not None } try: - GenericLiteLLMParams.model_validate(overrides, context=STRICT_LITELLM_PARAMS) + validate_litellm_params_strictly(GenericLiteLLMParams, overrides) except ValidationError as error: set_defaults: Final = {name: value for name, value in defaults.items() if value is not None} policy: Final = drop_policy({**deployment_params, **set_defaults, **request}) @@ -10628,8 +10628,8 @@ class Router: merged_params: Final[Mapping[str, object]] = ( _litellm_params if zeroed_pricing is None else MappingProxyType({**_litellm_params, **zeroed_pricing}) ) - litellm_params: Final[LiteLLM_Params] = LiteLLM_Params.model_validate( - dict(**merged_params), context=STRICT_LITELLM_PARAMS + litellm_params: Final[LiteLLM_Params] = validate_litellm_params_strictly( + LiteLLM_Params, dict(**merged_params) ) declared_params: Final = _LITELLM_PARAMS_ADAPTER.validate_python(_litellm_params) warn_on_provider_credential_mismatch(model_name=_model_name, litellm_params=declared_params) diff --git a/litellm/types/router.py b/litellm/types/router.py index 3a559f13cde..87a293fc4d2 100644 --- a/litellm/types/router.py +++ b/litellm/types/router.py @@ -24,6 +24,7 @@ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError import httpx from openai import Timeout as SDKTimeout from pydantic import ( + BaseModel, BeforeValidator, ConfigDict, Field, @@ -530,7 +531,15 @@ def holds_secret_pointer(param_name: str) -> bool: _RESERVED_INIT_KEYS: Final = frozenset({"self", "params", "__class__"}) -STRICT_LITELLM_PARAMS: Final = MappingProxyType({"strict_litellm_params": True}) +_STRICT_LITELLM_PARAMS: Final = MappingProxyType({"strict_litellm_params": True}) + +_StrictlyValidatedParams: Final = TypeVar("_StrictlyValidatedParams", bound=BaseModel) + + +def validate_litellm_params_strictly( + params_model: type[_StrictlyValidatedParams], params: Mapping[str, object] +) -> _StrictlyValidatedParams: + return params_model.model_validate(params, context=_STRICT_LITELLM_PARAMS) def _none_when_malformed_outside_strict_validation( @@ -539,7 +548,7 @@ def _none_when_malformed_outside_strict_validation( try: return handler(value) except ValidationError: - if info.context is STRICT_LITELLM_PARAMS: + if info.context is _STRICT_LITELLM_PARAMS: raise return None