BerriAI/litellm · error · HTTPException
Blocked by Gray Swan Guardrail
Error message
Blocked by Gray Swan Guardrail
What it means
fastapi HTTPException(400) raised from GraySwanGuardrail._process_grayswan_response when on_flagged_action is 'block' and the monitor response's violation score meets or exceeds violation_threshold. The detail payload carries structured diagnostics: violation_location (input vs output based on the hook), violation score, violated_rules, mutation, and ipi flags. The proxy surfaces it as an HTTP 400 whose body contains this detail dict.
Source
Thrown at litellm/proxy/guardrails/guardrail_hooks/grayswan/grayswan.py:344
"flagged": True,
"violation_score": violation_score,
"violated_rules": violated_rules,
"mutation": mutation_detected,
"ipi": ipi_detected,
}
# Determine if this is input (pre-call/during-call) or output (post-call)
if hook_type is not None:
is_input = hook_type in [
GuardrailEventHooks.pre_call,
GuardrailEventHooks.during_call,
]
else:
is_input = True
if self.on_flagged_action == "block":
violation_location: Final = "output" if (not is_input) else "input"
raise HTTPException(
status_code=400,
detail={
"error": GRAYSWAN_BLOCK_ERROR_MSG,
"violation_location": violation_location,
"violation": violation_score,
"violated_rules": violated_rules,
"mutation": mutation_detected,
"ipi": ipi_detected,
},
)
elif self.on_flagged_action == "passthrough":
# For passthrough mode, we need to handle violations
detections: Final = [detection_info]
violation_message: Final = self._format_violation_message(detections, is_output=not is_input)
verbose_proxy_logger.info("Gray Swan Guardrail: Passthrough mode - handling violation")
# If hook_type is provided and in pre/during call, raise exception
if hook_type in [View on GitHub (pinned to 77b7c6c40c)
Solutions
- Read the detail dict from the 400 body — violated_rules and violation score tell you which rule fired and by how much.
- Raise violation_threshold in the guardrail config so borderline content passes.
- Switch on_flagged_action to 'passthrough' to annotate metadata instead of blocking while you tune.
- Retune the specific violated rules in the GraySwan policy (or via policy_id/categories).
Example fix
# before litellm_params: guardrail: grayswan on_flagged_action: block violation_threshold: 0.1 # after litellm_params: guardrail: grayswan on_flagged_action: block violation_threshold: 0.6
Defensive patterns
Strategy: try-catch
Type guard
from fastapi import HTTPException
def is_grayswan_block(exc: BaseException) -> bool:
detail = getattr(exc, 'detail', None)
return isinstance(exc, HTTPException) and isinstance(detail, dict) and detail.get('error') == 'Blocked by Gray Swan Guardrail' Try / catch
from litellm.exceptions import BadRequestError
import json
try:
resp = client.chat.completions.create(model=model, messages=msgs)
except BadRequestError as e:
if 'Blocked by Gray Swan Guardrail' in str(e):
# proxy 400 body carries detail: violation, violated_rules, mutation, ipi
return {'blocked': True, 'raw': str(e)}
raise Prevention
- Start with on_flagged_action: passthrough while calibrating violation_threshold, then switch to block.
- Parse the violated_rules from the 400 detail to drive threshold tuning.
- Keep threshold changes versioned and reviewed like code.
When it happens
Trigger: pre_call/during_call hooks where user input scores >= violation_threshold; post_call hooks where model output exceeds it; prompt-injection or policy tests deliberately pushing scores over the line.
Common situations: violation_threshold set too low so borderline legitimate content is blocked; on_flagged_action left at 'block' when 'passthrough' (annotate but allow) was intended; users reporting 400s with 'Blocked by Gray Swan Guardrail' in the error body.
Related errors
- {blocked.explanation}
- Content violates policy
- Content violates policy
- {refusal}
- Violated CrowdStrike AIDR guardrail policy
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/c5ee792da73e9c43.
Report an issue: GitHub.