BerriAI/litellm · error · ValueError
otel.attributes: include_list and exclude_list are mutually
Error message
otel.attributes: include_list and exclude_list are mutually exclusive
What it means
The otel.attributes filter supports either include_list (export only these attributes) or exclude_list (export all but these) — never both, because their combination is ambiguous. _resolve_metric_attribute_filter raises ValueError when both are non-empty; empty lists and None are treated as unset, so an empty include_list alongside exclude_list is fine.
Source
Thrown at litellm/integrations/opentelemetry.py:179
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")
requested: Final = include or exclude or []
if TOKEN_TYPE_ATTRIBUTE in requested:
raise ValueError(
f"otel.attributes: {TOKEN_TYPE_ATTRIBUTE} is a structural token-usage discriminator and cannot be filtered"
)
unknown: Final = sorted(name for name in requested if name not in VALID_METRIC_ATTRIBUTE_NAMES)
if unknown:
raise ValueError(
f"otel.attributes: unknown attribute name(s) {unknown}. Valid names: {sorted(VALID_METRIC_ATTRIBUTE_NAMES)}"
)
return (
frozenset(include) if include else None,
frozenset(exclude) if exclude else None,
)
def _normalize_team_metadata_keys(value: Any) -> list[str]:
"""Coerce a team-metadata allowlist from a list or comma-separated string.View on GitHub (pinned to 6c2dcb801b)
Solutions
- Keep exactly one of include_list or exclude_list under otel.attributes
- Decide the strategy: allow-list for strict label control, deny-list to drop a few noisy labels
- If config comes from templates, ensure earlier keys are overridden, not merged
- Restart the proxy after correcting config.yaml
Example fix
# before
otel:
attributes:
include_list: [model, endpoint]
exclude_list: [api_key_hash] # ValueError: mutually exclusive
# after
otel:
attributes:
include_list: [model, endpoint] Defensive patterns
Strategy: validation
Validate before calling
def validate_otel_attributes(attrs: dict) -> None:
include = attrs.get("include_list") or None
exclude = attrs.get("exclude_list") or None
if include and exclude:
raise ValueError("choose include_list OR exclude_list, not both") Prevention
- Document one filtering strategy per team and template configs from a single source
- Reject merged Helm values that contain both lists
When it happens
Trigger: config.yaml with otel.attributes containing both include_list and exclude_list; config generated by templating that merges both keys; copying an example config that demonstrates both lists without removing one.
Common situations: Teams iterating on metric-label reduction and leaving both strategies in the YAML; Helm values merging defaults (exclude_list) with overrides (include_list).
Related errors
- otel.attributes must be a mapping with optional 'include_lis
- 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/c4b039b37149e566.
Report an issue: GitHub.