{"record":{"id":"8e224017c6c0ecf0","repo":"BerriAI/litellm","slug":"max-langfuse-clients-reached-litellm-initialized","errorCode":null,"errorMessage":"Max langfuse clients reached: {litellm.initialized_langfuse_clients} is greater than {MAX_LANGFUSE_INITIALIZED_CLIENTS}","messagePattern":"Max langfuse clients reached: (.+?) is greater than (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/integrations/langfuse/langfuse.py","lineNumber":216,"sourceCode":"                host=self.upstream_langfuse_host,\n                release=self.upstream_langfuse_release,\n                debug=(upstream_langfuse_debug if upstream_langfuse_debug is not None else False),\n            )\n        else:\n            self.upstream_langfuse = None\n\n    def safe_init_langfuse_client(self, parameters: dict) -> Langfuse:\n        \"\"\"\n        Safely init a langfuse client if the number of initialized clients is less than the max\n\n        Note:\n            - Langfuse initializes 1 thread everytime a client is initialized.\n            - We've had an incident in the past where we reached 100% cpu utilization because Langfuse was initialized several times.\n        \"\"\"\n        from langfuse import Langfuse\n\n        if litellm.initialized_langfuse_clients >= MAX_LANGFUSE_INITIALIZED_CLIENTS:\n            raise Exception(\n                f\"Max langfuse clients reached: {litellm.initialized_langfuse_clients} is greater than {MAX_LANGFUSE_INITIALIZED_CLIENTS}\"\n            )\n        langfuse_client: Final = Langfuse(**parameters)\n        litellm.initialized_langfuse_clients += 1\n        verbose_logger.debug(\"Created langfuse client number %s\", litellm.initialized_langfuse_clients)\n        return langfuse_client\n\n    @staticmethod\n    def add_metadata_from_header(litellm_params: dict, metadata: dict) -> dict:\n        \"\"\"\n        Adds metadata from proxy request headers to Langfuse logging if keys start with \"langfuse_\"\n        and overwrites litellm_params.metadata if already included.\n\n        For example if you want to append your trace to an existing `trace_id` via header, send\n        `headers: { ..., langfuse_existing_trace_id: your-existing-trace-id }` via proxy request.\n        \"\"\"\n        if litellm_params is None:\n            return metadata","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/langfuse/langfuse.py#L198-L234","documentation":"LiteLLM refuses to create more than MAX_LANGFUSE_INITIALIZED_CLIENTS Langfuse clients. Each Langfuse client spawns background threads, and litellm once hit 100% CPU from repeated client creation, so safe_init_langfuse_client enforces a hard cap. The counter is litellm.initialized_langfuse_clients, incremented on every successful init and never decremented in-process.","triggerScenarios":"Passing different langfuse_public_key/langfuse_secret/langfuse_host values per request via dynamic callback params (proxy headers such as x-litellm-langfuse-public-key), which forces a new client each time; repeatedly constructing LangfuseLogger instances in a long-lived process; many virtual keys each with their own langfuse credentials.","commonSituations":"Multi-tenant proxy setups where each team injects its own Langfuse credentials through request metadata/header overrides. After the cap of distinct credential sets is reached, every further request with new credentials raises this from the logging path.","solutions":["Consolidate to a single set of Langfuse credentials (set LANGFUSE_PUBLIC_KEY/LANGFUSE_SECRET_KEY globally instead of per-request dynamic params)","Remove per-request langfuse_* metadata/header overrides in the proxy so the shared client is reused","Restart the proxy process to reset litellm.initialized_langfuse_clients if it grew from historical churn","If distinct tenants are genuinely required, route different tenants to separate proxy deployments rather than one process"],"exampleFix":"# before (new client per request)\nmetadata = {\"langfuse_public_key\": tenant_pk, \"langfuse_secret\": tenant_sk}\nresponse = litellm.completion(..., metadata=metadata)\n\n# after (shared global client)\nimport os\nos.environ[\"LANGFUSE_PUBLIC_KEY\"] = shared_pk\nos.environ[\"LANGFUSE_SECRET_KEY\"] = shared_sk\nresponse = litellm.completion(...)  # reuses the single initialized client","handlingStrategy":"validation","validationCode":"import litellm\n\nMAX_CLIENTS = 50  # keep in sync with litellm's MAX_LANGFUSE_INITIALIZED_CLIENTS\n\ndef can_init_langfuse() -> bool:\n    return litellm.initialized_langfuse_clients < MAX_CLIENTS","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pass langfuse credentials per request; use global env vars","Monitor litellm.initialized_langfuse_clients in long-lived processes","Split genuinely multi-tenant Langfuse setups across proxy deployments"],"tags":["python","langfuse","resource-limit","callback","multi-tenant"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}