BerriAI/litellm · error · HTTPException

Microsoft Purview DLP: Content blocked by policy

Error message

Microsoft Purview DLP: Content blocked by policy

What it means

Intentional policy block: the Purview DLP evaluation succeeded and returned 'guardrail_intervened' (matched sensitive content), and the guardrail runs with block_on_violation, so the proxy rejects the request/response with HTTP 400 before the LLM output (or after it, for post-call hooks) is delivered. This is the guardrail working as designed, not a malfunction.

Source

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

                ) from exc
            verbose_proxy_logger.warning(
                "Purview DLP: API/network error in logging-only mode (not re-raised): %s",
                exc,
            )
        finally:
            end_time: Final = datetime.now()
            self.add_standard_logging_guardrail_information_to_request_data(
                guardrail_provider=self.guardrail_provider,
                guardrail_json_response=response,
                request_data=request_data,
                guardrail_status=status,
                start_time=start_time.timestamp(),
                end_time=end_time.timestamp(),
                duration=(end_time - start_time).total_seconds(),
            )

        if block_on_violation and status == "guardrail_intervened":
            raise HTTPException(
                status_code=400,
                detail={
                    "error": "Microsoft Purview DLP: Content blocked by policy",
                    "activity": activity,
                },
            )

        return response

    @staticmethod
    def _extract_responses_api_function_call_args(result: Any) -> list[str]:
        """Return tool-call argument strings from a ``ResponsesAPIResponse.output``.

        ``ResponsesAPIResponse.output_text`` only aggregates ``output_text``
        content blocks and ignores ``function_call`` items.  Model-generated
        tool-call arguments can themselves contain sensitive data, so we
        extract them explicitly to keep DLP coverage consistent with the
        chat (``ModelResponse``) path.

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Retrieve the matched policy details from Purview (activity id is included in the 'activity' field of the error detail) and either sanitize the input or request a policy exception
  2. If the content is legitimately allowed, have the Purview admin tune the DLP rule/threshold
  3. If you only want visibility, configure the guardrail for logging-only instead of blocking — but understand that removes the protection
  4. On the client: catch the 400 and surface a 'content blocked by data-loss-prevention policy' message to the end user

Example fix

# before: raw error surfaces to users
try:
    r = client.chat.completions.create(**params)
except Exception as e:
    raise RuntimeError(str(e))

# after: recognize the DLP block and degrade gracefully
from openai import BadRequestError
try:
    r = client.chat.completions.create(**params)
except BadRequestError as e:
    detail = e.response.json().get("detail", {})
    if isinstance(detail, dict) and detail.get("error") == "Microsoft Purview DLP: Content blocked by policy":
        return "Your message was blocked by the data-loss-prevention policy."
    raise
Defensive patterns

Strategy: try-catch

Validate before calling

null  # policy evaluation is server-side; nothing meaningful to pre-validate without duplicating Purview rules

Try / catch

from openai import BadRequestError

try:
    r = client.chat.completions.create(**params)
except BadRequestError as e:
    body = e.response.json()["detail"]
    if body.get("error") == "Microsoft Purview DLP: Content blocked by policy":
        activity = body.get("activity")  # correlation id for the Purview admin
        return user_friendly_block_page(activity)
    raise

Prevention

When it happens

Trigger: A pre-call request whose prompt/text contains content matching a Purview DLP policy (e.g. credit card numbers, classified strings); a post-call hook scanning the model response that trips a policy; guardrail configured with mode pre_call/post_call and default blocking semantics

Common situations: Internal apps red-teaming prompts with PII; a Purview admin tightened policies so previously-allowed traffic now trips; test suites sending synthetic sensitive data that matches default rules

Related errors


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