{"record":{"id":"1f10363ca0dbc15f","repo":"BerriAI/litellm","slug":"otel-attributes-token-type-attribute-is-a-struc","errorCode":null,"errorMessage":"otel.attributes: {TOKEN_TYPE_ATTRIBUTE} is a structural token-usage discriminator and cannot be filtered","messagePattern":"otel\\.attributes: (.+?) is a structural token-usage discriminator and cannot be filtered","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/integrations/opentelemetry.py","lineNumber":182,"sourceCode":"        )\n    return OTELMetricAttributeFilter(\n        include_list=value.get(\"include_list\"),\n        exclude_list=value.get(\"exclude_list\"),\n    )\n\n\ndef _resolve_metric_attribute_filter(\n    attributes: OTELMetricAttributeFilter | None,\n) -> tuple[frozenset[str] | None, frozenset[str] | None]:\n    if attributes is None:\n        return None, None\n    include: Final = attributes.include_list or None\n    exclude: Final = attributes.exclude_list or None\n    if include and exclude:\n        raise ValueError(\"otel.attributes: include_list and exclude_list are mutually exclusive\")\n    requested: Final = include or exclude or []\n    if TOKEN_TYPE_ATTRIBUTE in requested:\n        raise ValueError(\n            f\"otel.attributes: {TOKEN_TYPE_ATTRIBUTE} is a structural token-usage discriminator and cannot be filtered\"\n        )\n    unknown: Final = sorted(name for name in requested if name not in VALID_METRIC_ATTRIBUTE_NAMES)\n    if unknown:\n        raise ValueError(\n            f\"otel.attributes: unknown attribute name(s) {unknown}. Valid names: {sorted(VALID_METRIC_ATTRIBUTE_NAMES)}\"\n        )\n    return (\n        frozenset(include) if include else None,\n        frozenset(exclude) if exclude else None,\n    )\n\n\ndef _normalize_team_metadata_keys(value: Any) -> list[str]:\n    \"\"\"Coerce a team-metadata allowlist from a list or comma-separated string.\n\n    config.yaml passes a YAML list; an env var passes a comma-separated string.\n    Both collapse to a list of stripped, non-empty keys.","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/opentelemetry.py#L164-L200","documentation":"The token_type attribute (TOKEN_TYPE_ATTRIBUTE) is the structural discriminator LiteLLM's OTEL exporter uses to distinguish prompt/completion/cache token dimensions in token-usage metrics. Filtering it (via an exclude_list naming it, or any requested list containing it) would corrupt the metric shape, so _resolve_metric_attribute_filter explicitly rejects it.","triggerScenarios":"exclude_list containing the token_type attribute name; an include_list or exclude_list that includes it; copy-pasting an allow-list of common label names that happens to include it while trimming metric cardinality.","commonSituations":"Operators trying to reduce metric cardinality by trimming attributes and targeting token_type as 'just another label'; migrating from older litellm versions where this attribute was filterable.","solutions":["Remove the token_type attribute name from exclude_list","If using include_list, keep token_type in the allowed set (or switch to exclude_list for everything else you want dropped)","Reduce cardinality by filtering other attributes instead (see VALID_METRIC_ATTRIBUTE_NAMES in the error's sibling validation)","Keep config aligned with the installed litellm version's valid-name list shown in the unknown-attribute error"],"exampleFix":"# before\notel:\n  attributes:\n    exclude_list: [litellm_token_type_attribute]  # ValueError: structural discriminator\n\n# after\notel:\n  attributes:\n    exclude_list: [end_user, api_key_hash]  # filter non-structural attributes only","handlingStrategy":"validation","validationCode":"TOKEN_TYPE_ATTRIBUTE = \"litellm_token_type_attribute\"  # match the installed version's constant\nVALID = {\"model\", \"end_user\", \"api_key_hash\", \"api_provider\"}  # extend from your litellm version\n\ndef validate_otel_filter(attrs: dict) -> None:\n    requested = set(attrs.get(\"include_list\") or []) | set(attrs.get(\"exclude_list\") or [])\n    if TOKEN_TYPE_ATTRIBUTE in requested:\n        raise ValueError(f\"{TOKEN_TYPE_ATTRIBUTE} cannot be filtered\")\n    unknown = requested - VALID\n    if unknown:\n        raise ValueError(f\"unknown attributes: {sorted(unknown)}\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Read the error message for the exact valid attribute-name list on your litellm version","Treat structural metric labels as untouchable when trimming cardinality"],"tags":["python","opentelemetry","metrics","configuration","validation"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}