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
- 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
- If the content is legitimately allowed, have the Purview admin tune the DLP rule/threshold
- If you only want visibility, configure the guardrail for logging-only instead of blocking — but understand that removes the protection
- 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
- Map the 400 to a friendly 'content blocked by DLP' UX instead of surfacing raw error JSON
- Log the activity id so users can reference it when requesting policy exceptions
- Track block rates per key/team to catch over-broad policies early
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
- Request blocked by Onyx Guard. Violations: {detection_messag
- Violated OpenAI moderation policy
- guardrail_violation
- Content blocked: {category_name} conditional match '{matched
- Content blocked: {category_name} category keyword '{keyword}
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/9bf1ac0144e8d571.
Report an issue: GitHub.