From b83a1359991b292d0ea7c75eb80564b766c25d7d Mon Sep 17 00:00:00 2001 From: Maha Rana Yadavalli <271375718+maharanay22@users.noreply.github.com> Date: Fri, 9 Oct 2026 10:28:09 -0400 Subject: [PATCH] fix(proxy): keep internal callbacks when litellm_settings.callbacks is a single string When litellm_settings.callbacks was a single string instead of a list, the proxy overwrote litellm.callbacks with just that callback, dropping the internal callbacks registered at import, including the per-model max budget limiter. Keys with model_max_budget then went over budget without ever being blocked. The string form now appends, the same way the list form already extends --- litellm/proxy/common_utils/callback_utils.py | 4 ++-- tests/unit/proxy/common_utils/test_callback_utils.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/common_utils/callback_utils.py b/litellm/proxy/common_utils/callback_utils.py index 4fa7709e5c7..e3c4203c355 100644 --- a/litellm/proxy/common_utils/callback_utils.py +++ b/litellm/proxy/common_utils/callback_utils.py @@ -404,7 +404,7 @@ def initialize_callbacks_on_proxy( PrometheusLogger._mount_metrics_endpoint() else: - litellm.callbacks = [ + litellm.callbacks.append( _loaded_callback_or_raise( entry=value, loaded=get_instance_fn( @@ -412,7 +412,7 @@ def initialize_callbacks_on_proxy( config_file_path=config_file_path, ), ) - ] + ) verbose_proxy_logger.debug("%s Initialized Callbacks - %s %s", blue_color_code, litellm.callbacks, reset_color_code) diff --git a/tests/unit/proxy/common_utils/test_callback_utils.py b/tests/unit/proxy/common_utils/test_callback_utils.py index ecb2375d495..6ab1cfeec69 100644 --- a/tests/unit/proxy/common_utils/test_callback_utils.py +++ b/tests/unit/proxy/common_utils/test_callback_utils.py @@ -762,3 +762,15 @@ def test_initialize_callbacks_on_proxy_accepts_instance_non_list_value(probe_con assert len(litellm.callbacks) == 1 assert isinstance(litellm.callbacks[0], CustomLogger) + + +@pytest.mark.parametrize("as_list", [False, True], ids=["string_value", "list_value"]) +def test_initialize_callbacks_on_proxy_keeps_previously_registered_callbacks(probe_config_path: str, as_list: bool): + entry: Final = f"{_PROBE_MODULE_NAME}.proxy_handler_instance" + internal_callback: Final = CustomLogger() + litellm.callbacks.append(internal_callback) + + _load_callbacks([entry] if as_list else entry, probe_config_path) + + assert litellm.callbacks[0] is internal_callback + assert [type(cb).__name__ for cb in litellm.callbacks[1:]] == ["FloorMaxTokens"]