BerriAI/litellm · error · HTTPException
blocked_pii_entity
blocked_pii_entity
Error message
Blocked entity detected: {entity_type} by Guardrail: {guardrail_name}. This entity is not allowed to be used in this request. What it means
LiteLLM guardrail hooks inspect MCP tool calls before dispatch. When a PII guardrail running in blocking mode detects an entity type configured as blocked (for example an email address or phone number) in the request, it raises BlockedPiiEntityError, which this handler maps to HTTP 400 with error code blocked_pii_entity, including entity_type and guardrail_name.
Source
Thrown at litellm/proxy/_experimental/mcp_server/rest_endpoints.py:1056
verbose_logger.info(
"MCP tool call missing per-user env vars: server_id=%s missing=%s",
e.server_id,
e.missing,
)
raise HTTPException(
status_code=412,
detail={
"error": "missing_user_env_vars",
"message": str(e),
"server_id": e.server_id,
"server_name": e.server_name,
"missing": e.missing,
"setup_url": e.setup_url,
},
)
except BlockedPiiEntityError as e:
verbose_logger.error("BlockedPiiEntityError in MCP tool call: %s", e)
raise HTTPException(
status_code=400,
detail={
"error": "blocked_pii_entity",
"message": str(e),
"entity_type": getattr(e, "entity_type", None),
"guardrail_name": getattr(e, "guardrail_name", None),
},
)
except GuardrailRaisedException as e:
verbose_logger.error("GuardrailRaisedException in MCP tool call: %s", e)
raise HTTPException(
status_code=400,
detail={
"error": "guardrail_violation",
"message": str(e),
"guardrail_name": getattr(e, "guardrail_name", None),
},
)View on GitHub (pinned to 77b7c6c40c)
Solutions
- Remove or redact the blocked entity type from the tool arguments before sending.
- Ask the proxy admin to switch the guardrail from block to mask/correction mode, or drop that entity_type from blocked_entity_types.
- Route the workflow through a request tag whose guardrail set permits this data.
Defensive patterns
Strategy: validation
Validate before calling
import re
_PII_PATTERNS = {
"EMAIL_ADDRESS": re.compile(r"[\w.+-]+@[\w-]+\.[\w.]+"),
"PHONE_NUMBER": re.compile(r"\+?\d[\d\s().-]{7,}\d"),
}
def has_blocked_pii(text: str) -> list[str]:
return [name for name, rx in _PII_PATTERNS.items() if rx.search(text)]
hits = has_blocked_pii(json.dumps(arguments))
if hits:
redact_before_sending(hits) Type guard
def is_blocked_pii_response(resp_json: dict) -> bool:
d = resp_json.get("detail", {})
return isinstance(d, dict) and d.get("error") == "blocked_pii_entity" Try / catch
except httpx.HTTPStatusError as e:
d = e.response.json().get("detail", {})
if e.response.status_code == 400 and isinstance(d, dict) and d.get("error") == "blocked_pii_entity":
# entity_type and guardrail_name tell you exactly what tripped;
# redact and retry, or route the workflow elsewhere
log_pii_block(entity=d.get("entity_type"), guardrail=d.get("guardrail_name"))
return
raise Prevention
- Scan tool arguments for obvious PII (emails, phone numbers) before sending when a blocking guardrail is active.
- Prefer masked-credential fields over raw user contact data in MCP tool payloads.
- Ask the proxy admin which entity types are blocked so redaction targets the right data.
When it happens
Trigger: A guardrail with PII blocking (e.g., Presidio masking_config with blocked_entity_types, or block mode) is attached to the proxy, and the tool-call arguments contain a matching entity such as EMAIL_ADDRESS or PHONE_NUMBER.
Common situations: Org-wide guardrails rolled out after agent workflows were already built; CRM or messaging MCP tools (send email, create lead) receiving raw user contact data.
Related errors
- guardrail_violation
- invalid_request
- missing_parameter
- Request arguments are required
- Violated CrowdStrike AIDR guardrail policy
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/dff78d71bf98161a.
Report an issue: GitHub.