BerriAI/litellm · error · ValueError

{feature_name} only accepts identity headers from configured

Error message

{feature_name} only accepts identity headers from configured trusted proxy ranges. Direct client IP {direct_client_ip!r} is not trusted.

What it means

Even with trusted_proxy_ranges configured, LiteLLM validates the direct TCP peer of the connection (request.client.host) - not X-Forwarded-For - because the direct peer is the actor supplying the identity headers. If the socket IP falls outside every configured CIDR, the identity headers are rejected with this ValueError, after a warning log naming the rejected IP ('rejected identity headers from untrusted direct client IP ...').

Source

Thrown at litellm/proxy/auth/trusted_proxy_utils.py:80

    """
    if general_settings is None:
        general_settings = _get_proxy_general_settings()

    trusted_networks: Final = parse_trusted_proxy_ranges(general_settings.get(setting_name), setting_name=setting_name)
    if not trusted_networks:
        raise ValueError(
            f"{feature_name} requires general_settings.{setting_name} before "
            "trusting identity headers from an upstream proxy."
        )

    direct_client_ip: Final = _get_direct_client_ip(request)
    if not ip_in_networks(direct_client_ip, trusted_networks):
        verbose_proxy_logger.warning(
            "%s rejected identity headers from untrusted direct client IP %r",
            feature_name,
            direct_client_ip,
        )
        raise ValueError(
            f"{feature_name} only accepts identity headers from configured "
            f"trusted proxy ranges. Direct client IP {direct_client_ip!r} "
            "is not trusted."
        )

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Read the rejected IP from the proxy's warning log line ('rejected identity headers from untrusted direct client IP')
  2. Add that IP or its CIDR to general_settings.trusted_proxy_ranges and restart
  3. Ensure clients can only reach LiteLLM through the trusted proxy (network policy / private binding)
  4. For IPv6 peers, configure the matching IPv6 range

Example fix

# before
general_settings:
  trusted_proxy_ranges: ['10.0.0.0/8']   # warning: rejected identity headers from untrusted direct client IP '172.18.0.5'

# after
general_settings:
  trusted_proxy_ranges: ['10.0.0.0/8', '172.16.0.0/12']
Defensive patterns

Strategy: validation

Validate before calling

# Python: preflight - the peer your proxy server actually sees must be inside the configured ranges
import ipaddress
TRUSTED = [ipaddress.ip_network(c) for c in config['general_settings']['trusted_proxy_ranges']]
observed = request.client.host  # e.g. from a tiny echo middleware or access log
if not any(ipaddress.ip_address(observed) in n for n in TRUSTED):
    raise ValueError(f'direct peer {observed} not in trusted_proxy_ranges - fix config before enabling header identity')

Try / catch

try:
    await handle_oauth2_proxy_request(request)
except ValueError as e:
    if 'is not trusted' in str(e):
        # warning log already names the rejected direct client IP - add it (or its CIDR) to trusted_proxy_ranges
        log.warning('trusted-proxy mismatch: %s', e)
        return JSONResponse({'error': 'untrusted proxy source'}, status_code=400)
    raise

Prevention

When it happens

Trigger: The reverse proxy's egress IP is not in trusted_proxy_ranges (new LB node, autoscaled ingress pod outside the configured CIDR, Docker/K8s NAT address); or a client connects directly to LiteLLM while sending X-Forwarded-*/OAuth2 proxy headers.

Common situations: Kubernetes ingress pods spawn outside the configured pod CIDR; cloud LBs scale into new subnets; someone bypasses the proxy 'just for testing'; dual-stack setups where the connection arrives over IPv6 but only v4 ranges are configured.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/92236c52afb18590. Report an issue: GitHub.