BerriAI/litellm · error · HTTPException

Microsoft Purview DLP: No proxy-authenticated user identity;

Error message

Microsoft Purview DLP: No proxy-authenticated user identity; bind user_id to the API key for blocking DLP

What it means

The 'no identity at all' variant of Purview blocking-mode identity resolution: neither a trusted API-key-bound user id nor any caller-influenceable identity field was found, so the guardrail cannot attribute the request to an Entra user and rejects it with 400. Same fix as its sibling error — identity must be provisioned on the proxy side.

Source

Thrown at litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/purview_dlp.py:371

        only caller-influenceable identity fields are available (fail closed).
        """
        trusted_id: Final = self._resolve_trusted_user_id(data, user_api_key_dict)
        if trusted_id:
            return trusted_id

        if self._resolve_user_id(data, user_api_key_dict):
            raise HTTPException(
                status_code=400,
                detail={
                    "error": (
                        "Microsoft Purview DLP: No proxy-authenticated user identity; "
                        "bind user_id to the API key (caller-supplied metadata cannot "
                        "be used for blocking DLP)"
                    ),
                },
            )

        raise HTTPException(
            status_code=400,
            detail={
                "error": (
                    "Microsoft Purview DLP: No proxy-authenticated user identity; "
                    "bind user_id to the API key for blocking DLP"
                ),
            },
        )

    # ------------------------------------------------------------------
    # Pre-call hook — DLP on prompts
    # ------------------------------------------------------------------

    @log_guardrail_information
    async def async_pre_call_hook(
        self,
        user_api_key_dict: "UserAPIKeyAuth",
        cache: Any,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Create per-user (or per-service) virtual keys with user_id via /key/generate and use those keys for guarded routes
  2. If the caller legitimately has no user, still bind a stable service identity so Purview policy has an actor
  3. Keep master-key/admin traffic off Purview-guarded models, or give the admin key a user_id

Example fix

# before: shared key, no identity anywhere
client = OpenAI(api_key="sk-shared-no-user")

# after: dedicated key carrying identity
# curl -X POST $PROXY/key/generate -H "Authorization: Bearer $ADMIN" \
#   -d '{"user_id": "svc-billing", "key_duration": null}'
client = OpenAI(api_key=BOUND_SERVICE_KEY)
Defensive patterns

Strategy: validation

Validate before calling

# Fail fast in your client bootstrap: refuse to call guarded routes with unbound keys
async def assert_key_bound(proxy_admin: ProxyAdmin, key: str) -> None:
    user_id = await proxy_admin.get_key_user_id(key)
    if not user_id:
        raise RuntimeError(
            f"key {key[:8]}... has no bound user_id; Purview blocking DLP will reject it"
        )

Prevention

When it happens

Trigger: Requests through a shared/generic virtual key that was never associated with a user; direct calls with the master key; internal services calling the proxy without any user metadata

Common situations: Load tests or health checks hitting a Purview-guarded route with the admin key; service-to-service traffic with no user concept needing per-user DLP exemptions

Understand the failure class

Related errors


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