diff --git a/litellm/proxy/hooks/__init__.py b/litellm/proxy/hooks/__init__.py index 8714dd5f3d2..1ea843c86e5 100644 --- a/litellm/proxy/hooks/__init__.py +++ b/litellm/proxy/hooks/__init__.py @@ -1,6 +1,8 @@ import os from typing import Final, Literal +from litellm._logging import verbose_proxy_logger + from . import * from .cache_control_check import _PROXY_CacheControlCheck from .litellm_skills import SkillsInjectionHook @@ -47,10 +49,7 @@ def get_proxy_hook( try: from enterprise.enterprise_hooks import ENTERPRISE_PROXY_HOOKS -except ImportError: - ENTERPRISE_PROXY_HOOKS = {} - -### update PROXY_HOOKS with ENTERPRISE_PROXY_HOOKS ### - -PROXY_HOOKS.update(ENTERPRISE_PROXY_HOOKS) + PROXY_HOOKS.update(ENTERPRISE_PROXY_HOOKS) +except ImportError as e: + verbose_proxy_logger.warning("Could not import enterprise hooks — enterprise features disabled: %s", e) diff --git a/tests/test_litellm/proxy/hooks/test_proxy_hooks_init.py b/tests/test_litellm/proxy/hooks/test_proxy_hooks_init.py index a6edd3db944..4753b5fdb9b 100644 --- a/tests/test_litellm/proxy/hooks/test_proxy_hooks_init.py +++ b/tests/test_litellm/proxy/hooks/test_proxy_hooks_init.py @@ -49,3 +49,38 @@ def test_isolation_module_does_not_pull_in_proxy_utils(): importlib.import_module("litellm.llms.base_llm.managed_resources.isolation") assert "litellm.proxy.utils" not in sys.modules assert "litellm.proxy.management_endpoints.common_utils" not in sys.modules + +def test_enterprise_hooks_import_failure_logs_warning(monkeypatch, caplog): + """ + If the `enterprise` / `litellm_enterprise` package is unavailable + (e.g. missing from a hardened non_root Docker image), hooks/__init__.py + should log a warning and continue, instead of letting the ImportError + propagate and crash the whole proxy at import time. + """ + import builtins + import importlib + import logging + import sys + + real_import = builtins.__import__ + + def fake_import(name, *args, **kwargs): + if name == "enterprise" or name.startswith("enterprise."): + raise ImportError("No module named 'enterprise'") + return real_import(name, *args, **kwargs) + + monkeypatch.setattr(builtins, "__import__", fake_import) + sys.modules.pop("litellm.proxy.hooks", None) + + with caplog.at_level(logging.WARNING): + import litellm.proxy.hooks as hooks_module + importlib.reload(hooks_module) + + assert any( + "enterprise hooks" in record.message.lower() + for record in caplog.records + ), "Expected a warning to be logged when enterprise hooks import fails" + + monkeypatch.setattr(builtins, "__import__", real_import) + sys.modules.pop("litellm.proxy.hooks", None) + importlib.import_module("litellm.proxy.hooks")