{"record":{"id":"9ed412038581c219","repo":"BerriAI/litellm","slug":"callback-name-is-required-in-key-logging","errorCode":null,"errorMessage":"callback_name is required in key_logging","messagePattern":"callback_name is required in key_logging","errorType":"validation","errorClass":"ValueError","httpStatus":500,"severity":"error","filePath":"litellm/proxy/management_endpoints/key_management_endpoints.py","lineNumber":6548,"sourceCode":"    \"\"\"\n    Test the key-based logging\n\n    - Test that key logging is correctly formatted and all args are passed correctly\n    - Make a mock completion call -> user can check if it's correctly logged\n    - Check if any logger.exceptions were triggered -> if they were then returns it to the user client side\n    \"\"\"\n    import logging\n    from io import StringIO\n\n    from litellm.proxy.litellm_pre_call_utils import add_litellm_data_to_request\n    from litellm.proxy.proxy_server import general_settings, proxy_config\n\n    logging_callbacks: Final[list[str]] = []\n    for callback in key_logging:\n        if callback.get(\"callback_name\") is not None:\n            logging_callbacks.append(callback[\"callback_name\"])\n        else:\n            raise ValueError(\"callback_name is required in key_logging\")\n\n    log_capture_string: Final = StringIO()\n    ch: Final = logging.StreamHandler(log_capture_string)\n    ch.setLevel(logging.ERROR)\n    logger: Final = logging.getLogger()\n    logger.addHandler(ch)\n\n    try:\n        data = {\n            \"model\": \"openai/litellm-key-health-test\",\n            \"messages\": [\n                {\n                    \"role\": \"user\",\n                    \"content\": \"Hello, this is a test from litellm /key/health. No LLM API call was made for this\",\n                }\n            ],\n        }\n        data = await add_litellm_data_to_request(","sourceCodeStart":6530,"sourceCodeEnd":6566,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/key_management_endpoints.py#L6530-L6566","documentation":"Raised while preparing the per-key logging-callback health probe: every entry in the key's 'logging' metadata list must be a dict containing 'callback_name'; an entry without it cannot be mapped to a configured callback, so a ValueError aborts the check. It is raised inside the health-check try block, so the client actually receives it wrapped as 'Key health check failed: callback_name is required in key_logging' with status 500.","triggerScenarios":"Setting key metadata like {\"logging\": [{\"class\": \"my_pkg.MyLogger\"}]} or [{\"callback_type\": \"logger\"}] with no callback_name; hand-editing metadata JSON and dropping the field; older docs/examples that used a different key name for the callback.","commonSituations":"Custom callback integrations added via key metadata; migration from older LiteLLM metadata conventions; programmatic metadata assembly that conditionally omits the name.","solutions":["Ensure every element of metadata['logging'] includes 'callback_name', e.g. {\"callback_name\": \"litellm.proxy.custom_callbacks.my_handler.MyHandler\"}","Verify the named callback actually appears in proxy_logging_obj's loaded callbacks — otherwise fix config.yaml callback_settings/litellm_settings first","Update the key's metadata via /key/update rather than recreating the key","Re-run GET /key/health after fixing; the 500 wrapper disappears once the inner ValueError is gone"],"exampleFix":"# before\nawait client.post('/key/generate', json={\n    'metadata': {'logging': [{'class': 'my_pkg.MyLogger'}]}   # -> 500 Key health check failed: callback_name is required in key_logging\n})\n# after\nawait client.post('/key/generate', json={\n    'metadata': {'logging': [{'callback_name': 'my_pkg.MyLogger'}]}\n})","handlingStrategy":"validation","validationCode":"def validate_key_logging(logging_entries: list) -> None:\n    for i, entry in enumerate(logging_entries):\n        if not isinstance(entry, dict) or not entry.get('callback_name'):\n            raise ValueError(f\"logging[{i}] is missing required 'callback_name'\")","typeGuard":"def is_valid_key_logging(entries: object) -> bool:\n    return (\n        isinstance(entries, list)\n        and all(isinstance(e, dict) and isinstance(e.get('callback_name'), str) and e['callback_name'] for e in entries)\n    )","tryCatchPattern":"try:\n    await client.post('/key/generate', json=payload_with_logging_metadata)\nexcept httpx.HTTPStatusError as e:\n    if 'callback_name is required' in e.response.text:\n        raise ValueError('fix metadata.logging entries: each needs callback_name') from e\n    raise","preventionTips":["Generate logging metadata from a single typed helper that always sets callback_name","Assert the callback exists in config.yaml callback settings before attaching it to keys","Run GET /key/health in CI for a sample key to catch metadata problems early"],"tags":["key-logging","metadata","callbacks","litellm-proxy","validation"],"backgroundTag":"missing-required-field","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}