BerriAI/litellm · error · HTTPException
guardrail_violation
guardrail_violation
Error message
guardrail_violation
What it means
GuardrailRaisedException is the generic guardrail rejection: an active guardrail (preset or custom) raised during the pre-call check of an MCP tool call. This handler converts it to HTTP 400 with error code guardrail_violation plus guardrail_name. It differs from blocked_pii_entity in that it covers any blocking guardrail decision, not only PII entity blocking.
Source
Thrown at litellm/proxy/_experimental/mcp_server/rest_endpoints.py:1067
"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),
},
)
except MCPUpstreamAuthError as e:
# A client-forwarded pass-through upstream 401 from either the direct or the virtual call
# branch. Relay it as a 401 + WWW-Authenticate so the MCP client can re-run upstream OAuth,
# and log at info: an expected caller-must-reauth signal, not an operator-actionable error.
verbose_logger.info("MCP tool call relaying upstream HTTP %s", e.status_code)
raise _relay_upstream_auth_http_exception(e, request)
except HTTPException as e:
# Locally generated denials (tool/server permission, IP filtering, BYOK) stay at error level
# so restriction probing keeps full monitoring visibility; the relayed upstream 401 above is
# the only status demoted to info.
verbose_logger.error("HTTPException in MCP tool call: %s", e)View on GitHub (pinned to 77b7c6c40c)
Solutions
- Read guardrail_name from the response and check that guardrail's logs to see which rule matched.
- Change the request content to satisfy the rule (remove banned terms/URLs/topics).
- Ask the admin to scope the guardrail so it does not block legitimate MCP tool traffic, or to adjust the rule thresholds.
Defensive patterns
Strategy: try-catch
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") == "guardrail_violation":
# guardrail_name identifies the rule set; do not blind-retry — content must change
raise PolicyRejected(guardrail=d.get("guardrail_name"), reason=str(d.get("message"))) from e
raise Prevention
- Treat 400 guardrail_violation as permanent for that payload — change the content, do not retry unchanged.
- Keep a mapping of active guardrails and their rules so tool payloads are pre-cleaned.
- Log guardrail_name with every rejection to spot over-broad rules early.
When it happens
Trigger: A guardrail in blocking mode (banned keywords/URLs/topics, prompt-injection or jailbreak detection) matches content in the tool call; guardrail hooks run inside the pre-call check and reject the request before it reaches the upstream MCP server.
Common situations: A security team enables strict guardrails on all traffic including MCP tools; agent prompts that quote untrusted web content trip keyword rules.
Related errors
- blocked_pii_entity
- Content blocked: {category_name} conditional match '{matched
- Content blocked: {category_name} category keyword '{keyword}
- Content blocked: {pattern_name} pattern detected
- Content blocked: keyword '{keyword}' detected
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/571aa0b4000af34a.
Report an issue: GitHub.