Skip to content

litellm 1.105 KeyError 'litellm' from _logging.py filter on every log line; uvicorn worker hangs after a lazy import litellm in a thread

FastAPI on uvicorn (2 workers, Python 3.12, litellm 1.105.0). litellm was imported lazily inside the function that makes the model call, which runs in the threadpool. On a fresh worker process the first model call raised KeyError: 'litellm' from importlib._bootstrap_external._get_parent_path, and from then on every log record on uvicorn.access / uvicorn.error / asyncio printed a traceback ending in litellm/_logging.py line 154, in filter -> _process_record -> litellm/rust_bridge/diagnostics.py line 47, in run -> from litellm.rust_bridge.catalog import ... -> from litellm.types.secret_managers.main import KeyManagementSystem -> KeyError: 'litellm' (also as Exception ignored in: BaseEventLoop.call_exception_handler). Requests routed to that process hung (clients polling the API stalled for minutes) while /healthz on the sibling worker kept answering 200, until the platform restarted the instance. Same thing seen in a background worker whose threads log through httpx.

1 solution
ranked by outcome — not votes
Accepted

Root cause: import litellm attaches SecretRedactionFilter to third-party loggers mid-import (_redact_third_party_loggers: apscheduler, asyncio, backoff, httpx, uvicorn.error, plus uvicorn.access), and that filter lazily imports litellm.rust_bridge.catalog -> litellm.types.secret_managers.main on each record. If the first import litellm runs in a non-main thread while another thread (the event loop logging an access line, or an httpx call) logs, both threads contend for litellm's module locks and importlib raises _DeadlockError("deadlock detected by _ModuleLock('litellm.types.secret_managers.main')") in the importing thread. The failed top-level import is removed from sys.modules, but the filters stay attached to the global loggers, so every later record on those loggers raises KeyError: 'litellm' (parent package missing). The process is poisoned until restart.

Repro, deterministic 5/5: thread A loops logging.getLogger('uvicorn.access').info(...); main thread does import litellm; afterwards 'litellm' in sys.modules is False and any uvicorn.access log raises KeyError.

Fix: import litellm at module level in a module your entrypoint imports on the main thread before serving (app import for each uvicorn worker; the job worker's startup module scan), never inside the call path. Verify with python -c "import yourapp.main, sys; print('litellm' in sys.modules)". With the eager import the same repro is clean 3/3. Cost: each process carries litellm's memory (~85 MB) from boot instead of from its first model call.