{"record":{"id":"3df6ed53cd901d58","repo":"BerriAI/litellm","slug":"callback-param-param-from-source-contains","errorCode":null,"errorMessage":"Callback param '{param}' (from {source}) contains an 'os.environ/' reference. Environment references in request-supplied parameters are no longer resolved server-side for security reasons.\\nTo resolve:\\n  1. Remove the 'os.environ/' reference from your request body / metadata.\\n  2. Either (a) configure this callback value in your proxy config.yaml under 'litellm_settings' / 'general_settings', or (b) pass the resolved secret value directly in the request.\\nSee https://docs.litellm.ai/docs/proxy/logging for server-side callback configuration.","messagePattern":"Callback param '\\{param\\}' \\(from \\{source\\}\\) contains an 'os\\.environ/' reference\\. Environment references in request-supplied parameters are no longer resolved server-side for security reasons\\.\\\\nTo resolve:\\\\n  1\\. Remove the 'os\\.environ/' reference from your request body / metadata\\.\\\\n  2\\. Either \\(a\\) configure this callback value in your proxy config\\.yaml under 'litellm_settings' / 'general_settings', or \\(b\\) pass the resolved secret value directly in the request\\.\\\\nSee https://docs\\.litellm\\.ai/docs/proxy/logging for server-side callback configuration\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/initialize_dynamic_callback_params.py","lineNumber":28,"sourceCode":"    kwargs: dict[str, Any],\n) -> Iterator[tuple[str, dict[str, Any]]]:\n    litellm_params: Final = kwargs.get(\"litellm_params\")\n    if isinstance(litellm_params, dict):\n        nested: Final = litellm_params.get(\"metadata\")\n        if isinstance(nested, dict):\n            yield \"litellm_params.metadata\", nested\n    for key in _CLIENT_CALLBACK_METADATA_SLOTS:\n        candidate = kwargs.get(key)\n        if isinstance(candidate, dict):\n            yield key, candidate\n\n\ndef _is_env_reference(value: object) -> bool:\n    return isinstance(value, str) and \"os.environ/\" in value\n\n\ndef _raise_env_reference_error(param: str, *, source: str) -> None:\n    raise ValueError(\n        f\"Callback param '{param}' (from {source}) contains an 'os.environ/' \"\n        \"reference. Environment references in request-supplied parameters are \"\n        \"no longer resolved server-side for security reasons.\\n\"\n        \"To resolve:\\n\"\n        \"  1. Remove the 'os.environ/' reference from your request body / \"\n        \"metadata.\\n\"\n        \"  2. Either (a) configure this callback value in your proxy \"\n        \"config.yaml under 'litellm_settings' / 'general_settings', or \"\n        \"(b) pass the resolved secret value directly in the request.\\n\"\n        \"See https://docs.litellm.ai/docs/proxy/logging for server-side \"\n        \"callback configuration.\"\n    )\n\n\ndef validate_no_callback_env_reference(param: str, value: object, *, source: str) -> None:\n    if _is_env_reference(value):\n        _raise_env_reference_error(param, source=source)\n","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/initialize_dynamic_callback_params.py#L10-L46","documentation":"A deliberate security hardening error: LiteLLM no longer resolves 'os.environ/...' references found in request-supplied callback parameters (e.g. metadata like langfuse_secret_key sent in the request body). Resolving env refs server-side from untrusted request bodies lets any caller exfiltrate arbitrary environment variables (secrets) through callback configs, so the value is now rejected instead of expanded.","triggerScenarios":"Sending a chat/completions (or embeddings) request whose litellm_params.metadata or callback-related fields contain a string with 'os.environ/' in it — e.g. metadata: {\"langfuse_secret_key\": \"os.environ/LANGFUSE_KEY\"} — on a LiteLLM version that includes initialize_dynamic_callback_params.py.","commonSituations":"Upgrading LiteLLM/proxy to a version containing this security change while client code still injects per-request callback credentials via os.environ references; migrating from the old documented per-request metadata pattern for langfuse/langsmith keys.","solutions":["Move callback credentials to the proxy config.yaml under litellm_settings (callbacks + their env vars) or general_settings, and let the server resolve its own environment","Or have the client send the already-resolved secret value directly in the request instead of the 'os.environ/NAME' indirection","Remove any 'os.environ/' strings from request bodies/metadata; scan client code for the literal 'os.environ/' before upgrading"],"exampleFix":"# before (request body)\ncurl -X POST /v1/chat/completions -d '{\n  \"model\": \"gpt-4o\",\n  \"messages\": [...],\n  \"metadata\": {\"langfuse_secret_key\": \"os.environ/LANGFUSE_KEY\"}\n}'\n\n# after (config.yaml — server-side resolution)\nlitellm_settings:\n  callbacks: [\"langfuse\"]\n# langfuse env vars set in the proxy's environment: LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY","handlingStrategy":"validation","validationCode":"def assert_no_env_refs(payload: dict) -> None:\n    def walk(node):\n        if isinstance(node, dict):\n            for v in node.values(): walk(v)\n        elif isinstance(node, list):\n            for v in node: walk(v)\n        elif isinstance(node, str) and 'os.environ/' in node:\n            raise ValueError(f\"os.environ/ reference in request payload: {node!r}\")\n    walk(payload)\n\nassert_no_env_refs(request_body)  # call before litellm.acompletion(**request_body)","typeGuard":null,"tryCatchPattern":"try:\n    litellm.acompletion(**params)\nexcept ValueError as e:\n    if 'os.environ/' in str(e) and 'no longer resolved server-side' in str(e):\n        params['metadata'].pop('langfuse_secret_key')  # move to config.yaml\n        litellm.acompletion(**params)\n    else:\n        raise","preventionTips":["Configure all callback credentials server-side (config.yaml / env) before upgrading","Grep clients for 'os.environ/' strings before deploying a newer proxy","Never pass secrets by naming env vars in request bodies"],"tags":["litellm","security","callbacks","os-environ","proxy","upgrade"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}