{"record":{"id":"b5f643f8f6671d62","repo":"BerriAI/litellm","slug":"internal-error-cache-cannot-be-empty-internal-u","errorCode":null,"errorMessage":"Internal Error: Cache cannot be empty - internal_usage_cache={internal_usage_cache}","messagePattern":"Internal Error: Cache cannot be empty - internal_usage_cache=(.+?)","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/litellm_logging.py","lineNumber":4135,"sourceCode":"            )\n            for callback in _in_memory_loggers:\n                # Use exact type check to avoid matching ArizePhoenixLogger (subclass)\n                if type(callback) is OpenTelemetry:\n                    return callback\n            _otel_logger = OpenTelemetry(config=otel_config)\n            _in_memory_loggers.append(_otel_logger)\n            return _otel_logger\n        elif logging_integration == \"dynamic_rate_limiter\":\n            from litellm.proxy.hooks.dynamic_rate_limiter import (\n                _PROXY_DynamicRateLimitHandler,\n            )\n\n            for callback in _in_memory_loggers:\n                if isinstance(callback, _PROXY_DynamicRateLimitHandler):\n                    return callback\n\n            if internal_usage_cache is None:\n                raise Exception(f\"Internal Error: Cache cannot be empty - internal_usage_cache={internal_usage_cache}\")\n\n            dynamic_rate_limiter_obj: Final = _PROXY_DynamicRateLimitHandler(internal_usage_cache=internal_usage_cache)\n\n            if llm_router is not None and isinstance(llm_router, litellm.Router):\n                dynamic_rate_limiter_obj.update_variables(llm_router=llm_router)\n            _in_memory_loggers.append(dynamic_rate_limiter_obj)\n            return dynamic_rate_limiter_obj\n        elif logging_integration == \"dynamic_rate_limiter_v3\":\n            from litellm.proxy.hooks.dynamic_rate_limiter_v3 import (\n                _PROXY_DynamicRateLimitHandlerV3,\n            )\n\n            for callback in _in_memory_loggers:\n                if isinstance(callback, _PROXY_DynamicRateLimitHandlerV3):\n                    return callback\n\n            if internal_usage_cache is None:\n                raise Exception(f\"Internal Error: Cache cannot be empty - internal_usage_cache={internal_usage_cache}\")","sourceCodeStart":4117,"sourceCodeEnd":4153,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/litellm_logging.py#L4117-L4153","documentation":"The 'dynamic_rate_limiter' callback is a proxy hook that reads project/team usage from the proxy's shared Redis-backed internal usage cache; it cannot function without one. When LiteLLM lazily instantiates _PROXY_DynamicRateLimitHandler and internal_usage_cache is None (no proxy cache configured), it raises this Exception. The 'Internal Error' prefix signals a server-side configuration gap rather than a request problem.","triggerScenarios":"Adding 'dynamic_rate_limiter' to litellm_settings.callbacks (or default callbacks) in a LiteLLM proxy config.yaml that has no cache: block (no Redis URL / internal_usage_cache host), then triggering the first logged request.","commonSituations":"Copy-pasting a config that includes the dynamic rate limiter without the Redis section it was written against; running the proxy locally without Redis; Redis env vars present but the cache: block missing so the internal usage cache is never constructed.","solutions":["Configure a proxy cache in config.yaml (cache: type: redis, url / redis env vars) so the internal usage cache exists, then restart","Or remove 'dynamic_rate_limiter' from callbacks if you don't intend to use usage-based dynamic rate limiting","Verify Redis connectivity from the proxy container (redis-cli ping) since a failed cache init also leaves internal_usage_cache None","Check proxy startup logs for cache initialization errors preceding this one"],"exampleFix":"# before\nlitellm_settings:\n  callbacks: [\"dynamic_rate_limiter\"]   # Exception: Cache cannot be empty\n\n# after\nlitellm_settings:\n  callbacks: [\"dynamic_rate_limiter\"]\ncache:\n  type: redis\n  url: redis://redis:6379","handlingStrategy":"validation","validationCode":"# config-level guard: only enable dynamic rate limiting when a cache is configured\nimport yaml\ncfg = yaml.safe_load(open('config.yaml'))\nhas_cache = 'cache' in cfg and cfg['cache'].get('type') == 'redis'\ncallbacks = cfg.get('litellm_settings', {}).get('callbacks', [])\nassert not ('dynamic_rate_limiter' in callbacks and not has_cache), \\\n    'dynamic_rate_limiter requires a Redis cache block in config.yaml'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pair dynamic_rate_limiter with a cache: redis block in the same config","Monitor proxy startup logs for cache initialization failures","Don't enable proxy-only dynamic rate limiter callbacks when using litellm as a library"],"tags":["litellm","rate-limiting","redis","proxy","configuration"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}