BerriAI/litellm · error · ValueError
otel.attributes must be a mapping with optional 'include_lis
Error message
otel.attributes must be a mapping with optional 'include_list' / 'exclude_list', got {type(value).__name__} What it means
LiteLLM's OpenTelemetry metric attribute filter is configured via 'otel.attributes', which must be a mapping (dict) optionally containing include_list/exclude_list. _build_metric_attribute_filter accepts an already-built OTELMetricAttributeFilter or a dict; any other type (str, list, tuple, or a bad YAML parse) raises ValueError naming the offending type.
Source
Thrown at litellm/integrations/opentelemetry.py:161
"gen_ai.request.model",
"gen_ai.framework",
"hidden_params",
)
+ tuple(f"metadata.{key}" for key in METRIC_METADATA_KEYS)
)
@dataclass(frozen=True)
class OTELMetricAttributeFilter:
include_list: list[str] | None = None
exclude_list: list[str] | None = None
def _build_metric_attribute_filter(value: Any) -> OTELMetricAttributeFilter:
if isinstance(value, OTELMetricAttributeFilter):
return value
if not isinstance(value, dict):
raise ValueError(
"otel.attributes must be a mapping with optional 'include_list' / "
f"'exclude_list', got {type(value).__name__}"
)
return OTELMetricAttributeFilter(
include_list=value.get("include_list"),
exclude_list=value.get("exclude_list"),
)
def _resolve_metric_attribute_filter(
attributes: OTELMetricAttributeFilter | None,
) -> tuple[frozenset[str] | None, frozenset[str] | None]:
if attributes is None:
return None, None
include: Final = attributes.include_list or None
exclude: Final = attributes.exclude_list or None
if include and exclude:
raise ValueError("otel.attributes: include_list and exclude_list are mutually exclusive")View on GitHub (pinned to 6c2dcb801b)
Solutions
- Use a mapping: otel: attributes: {include_list: [model, api_provider]} (or exclude_list)
- Check YAML indentation so 'attributes:' is a key under 'otel:' with list values beneath it
- Do not pass a string or list directly as the attributes value
- After fixing, restart the proxy; config is parsed at startup so a stale config file will keep failing
Example fix
# before (config.yaml)
otel:
attributes: model,api_provider # ValueError: ...got str
# after
otel:
attributes:
include_list:
- model
- api_provider Defensive patterns
Strategy: type-guard
Validate before calling
def valid_otel_attributes(cfg: object) -> bool:
return cfg is None or isinstance(cfg, dict) or hasattr(cfg, "include_list") Type guard
from typing import Any
def is_otel_attributes_mapping(value: Any) -> bool:
return isinstance(value, dict) and set(value) <= {"include_list", "exclude_list"} Prevention
- Lint proxy config.yaml against a schema before deploying
- Use structured config validation for nested tool config like otel.attributes
When it happens
Trigger: Writing 'otel.attributes: include_list' (a bare string) in proxy YAML; passing a list of names like 'otel.attributes: [model, endpoint]'; YAML indentation that parses attributes into a scalar instead of a mapping.
Common situations: Configuring Prometheus/OpenTelemetry metric label filtering in litellm proxy config.yaml; authors assuming a comma-separated string or flat list is accepted; YAML indentation mistakes nesting the keys under the wrong parent.
Related errors
- otel.attributes: include_list and exclude_list are mutually
- otel.attributes: {TOKEN_TYPE_ATTRIBUTE} is a structural toke
- duration needs to be one of ["daily", "weekly", "monthly", "
- LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY must be set for
- Invalid mode: {custom_auth_settings['mode']}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/65d2910fb4703e7e.
Report an issue: GitHub.