From 9f9e21d463e18d6da697b0b99a95de6ef2805b2d Mon Sep 17 00:00:00 2001 From: user <70670632+stuxf@users.noreply.github.com> Date: Wed, 13 May 2026 18:29:42 +0000 Subject: [PATCH] fix(proxy): thread config_file_path through LiteLLM_JWTAuth.custom_validate LiteLLM_JWTAuth.__init__ calls get_instance_fn(custom_validate) without config_file_path, so an operator who configures custom_validate: s3://bucket/module.fn in their YAML JWT auth section would hit the runtime gate on startup and break their deployment. Accept config_file_path as a non-field kwarg (popped before the invalid-keys check), thread it into get_instance_fn, and pass it from the startup-load callsite via the existing user_config_file_path module-level path. Admin-API JWT config writes leave the kwarg at None and still hit the gate. --- litellm/proxy/_types.py | 10 +++++++++- litellm/proxy/proxy_server.py | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index 6128f48574..3fdc4c35e0 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -4486,6 +4486,14 @@ class LiteLLM_JWTAuth(LiteLLMPydanticObjectBase): ######################################################### def __init__(self, **kwargs: Any) -> None: + # ``config_file_path`` is a non-field kwarg threaded by the + # startup-load path so an operator-configured + # ``custom_validate: s3://bucket/module.fn`` resolves through + # the documented config-file flow. Pop before the invalid-keys + # check; the runtime gate in ``get_instance_fn`` refuses + # ``s3://`` / ``gcs://`` when this is None. + config_file_path = kwargs.pop("config_file_path", None) + # get the attribute names for this Pydantic model allowed_keys = LiteLLM_JWTAuth.__annotations__.keys() @@ -4499,7 +4507,7 @@ class LiteLLM_JWTAuth(LiteLLMPydanticObjectBase): custom_validate = kwargs.get("custom_validate") if custom_validate is not None: - fn = get_instance_fn(custom_validate) + fn = get_instance_fn(custom_validate, config_file_path=config_file_path) validate_custom_validate_return_type(fn) kwargs["custom_validate"] = fn diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index adfac4dffd..9c9c00d59c 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -6774,7 +6774,15 @@ class ProxyStartupEvent: for k, v in general_settings["litellm_jwtauth"].items(): if isinstance(v, str) and v.startswith("os.environ/"): general_settings["litellm_jwtauth"][k] = get_secret(v) - litellm_jwtauth = LiteLLM_JWTAuth(**general_settings["litellm_jwtauth"]) + # ``user_config_file_path`` is set by ``ProxyConfig._get_config_from_file`` + # during startup. Threading it through lets an operator- + # configured ``custom_validate: s3://...`` resolve through + # the runtime gate; admin-API JWT config writes (no config + # file context) hit the gate and refuse remote loads. + litellm_jwtauth = LiteLLM_JWTAuth( + config_file_path=user_config_file_path, + **general_settings["litellm_jwtauth"], + ) else: litellm_jwtauth = LiteLLM_JWTAuth() jwt_handler.update_environment(