BerriAI/litellm · error · ValueError

Cannot route sensitive data without a session_id. Ensure…

Error message

Cannot route sensitive data without a session_id. Ensure the request includes a session_id in metadata or headers.

What it means

For sensitive-data rerouting, CustomGuardrail.raise_sensitive_data_route_exception() must bind the flagged request to a sticky session on the alternate model. It first extracts a session id from the request data via get_session_id_from_request_data (metadata.session_id or the session headers); when none is found it raises this ValueError before the rerouting SensitiveDataRouteException is ever raised.

Solutions

  1. Send metadata={'session_id': '<stable id>'} (or the proxy's session header) on every request that may carry sensitive data
  2. Fix header/metadata propagation through your gateway so the session id survives to the guardrail
  3. If traffic is genuinely sessionless, disable sensitive-data routing and use plain blocking/masking mode

Example fix

# before
response = litellm.acompletion(model='gpt-4o', messages=[...])  # no session id -> ValueError on detection

# after
response = litellm.acompletion(
    model='gpt-4o', messages=[...],
    metadata={'session_id': user_conversation_id},  # enables sticky rerouting
)
Defensive patterns

Strategy: validation

Validate before calling

sid = request_data.get('metadata', {}).get('session_id')
if not sid:
    raise HTTPException(400, 'session_id required when sensitive-data routing is enabled')
await guardrail.raise_sensitive_data_route_exception(route_to_model, request_data, detection_info)

Type guard

def has_session_id(request_data: dict) -> bool:
    meta = request_data.get('metadata') or {}
    return bool(meta.get('session_id')) or bool(request_data.get('headers'))

Try / catch

except ValueError as e:
    if 'session_id' in str(e):
        retry the call once after attaching metadata={'session_id': str(uuid4())}
    else:
        raise

Prevention

When it happens

Trigger: Guardrail configured with sensitive_data_route_to_model and a request arrives without metadata['session_id'] and without a session header; direct SDK/API calls into the proxy that never established a session; session field name typos like 'sessionId' in metadata.

Common situations: Enabling sensitive-data routing on an existing traffic stream that does not yet propagate session ids; clients migrated from raw completions calls with no session concept; gateway stripping custom headers including the session one.

Related errors


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

Appendix: source

Thrown at litellm/integrations/custom_guardrail.py:277

        to route to an on-premise model instead of blocking.

        The exception will reroute this request to the specified model. When
        sticky_session_routing is enabled (the default), it also stores the
        routing decision so subsequent requests in this session reuse the model.

        Args:
            route_to_model: The model to route this request (and session) to
            request_data: The original request data dictionary
            detection_info: Optional non-sensitive detection metadata (e.g. matched
                entity types, rule ids, scores). This is surfaced in request metadata
                and logs, so it must not contain the raw detected sensitive values.

        Raises:
            SensitiveDataRouteException: Always raises to trigger rerouting
        """
        session_id: Final = self._get_session_id_from_request_data(request_data)
        if not session_id:
            raise ValueError(
                "Cannot route sensitive data without a session_id. "
                "Ensure the request includes a session_id in metadata or headers."
            )

        raise SensitiveDataRouteException(
            route_to_model=route_to_model,
            session_id=session_id,
            guardrail_name=self.guardrail_name,
            detection_info=detection_info,
            sticky_session_routing=self.sticky_session_routing,
        )

    def _get_session_id_from_request_data(self, request_data: dict[str, Any]) -> str | None:
        """Extract session_id from request data."""
        return get_session_id_from_request_data(request_data)

    @staticmethod
    def _scanned_text_hash(text: str) -> str:

View on GitHub (pinned to 77b7c6c40c)