BerriAI/litellm · error · HTTPException
Violated OpenAI moderation policy
Error message
Violated OpenAI moderation policy
What it means
Intentional content block from OpenAIModerationGuardrail._check_moderation_result: the moderation model flagged the text in one or more categories, and the guardrail (running in blocking mode) rejects the request/response with HTTP 400. The detail includes which categories fired and the full category_scores for auditability.
Source
Thrown at litellm/proxy/guardrails/guardrail_hooks/openai/moderations.py:161
if result.flagged:
# Build detailed violation information
violated_categories: Final = []
if result.categories:
for category, is_violated in result.categories.items():
if is_violated:
violated_categories.append(category)
violation_details: Final = {
"violated_categories": violated_categories,
"category_scores": result.category_scores or {},
}
verbose_proxy_logger.warning(
"OpenAI Moderation: Content flagged for violations: %s",
violation_details,
)
raise HTTPException(
status_code=400,
detail={
"error": "Violated OpenAI moderation policy",
"moderation_result": violation_details,
},
)
@log_guardrail_information
async def apply_guardrail(
self,
inputs: GenericGuardrailAPIInputs,
request_data: dict,
input_type: Literal["request", "response"],
logging_obj: Optional["LiteLLMLoggingObj"] = None,
) -> GenericGuardrailAPIInputs:
"""
Apply OpenAI moderation guardrail using the unified guardrail interface.
View on GitHub (pinned to 77b7c6c40c)
Solutions
- Catch the 400 client-side and degrade gracefully using violated_categories to tailor the message
- For legitimate content being over-flagged, pre-filter or rephrase at the application layer, or run the guardrail in log-only mode for those routes
- Review category_scores — near-threshold scores indicate borderline content you may choose to allow by switching to custom threshold handling
- Keep human-review flows for false positives rather than bypassing moderation entirely
Example fix
# before: error propagates raw
try:
r = client.chat.completions.create(**params)
except Exception:
abort(500)
# after: handle the moderation block specifically
from openai import BadRequestError
try:
r = client.chat.completions.create(**params)
except BadRequestError as e:
body = e.response.json()
if body.get("error") == "Violated OpenAI moderation policy":
cats = body["moderation_result"]["violated_categories"]
return f"Content blocked ({', '.join(cats)}). Please rephrase.", 400
raise Defensive patterns
Strategy: try-catch
Validate before calling
null # moderation verdict is server-side; clients cannot pre-classify without reimplementing the model
Try / catch
from openai import BadRequestError
try:
r = client.chat.completions.create(**params)
except BadRequestError as e:
body = e.response.json()
if body.get("error") == "Violated OpenAI moderation policy":
cats = body["moderation_result"]["violated_categories"]
return respond_block_page(cats)
raise Prevention
- Convert the 400 into category-aware user messaging instead of retrying — the same input will fail again
- Log category_scores to spot systematic false positives and take them to policy review
- Keep fixtures with known-flaggy strings in your test suite to assert your block-handling path works
When it happens
Trigger: Pre-call moderation of prompts containing violence/self-harm/hate/sexual content matched by omni-moderation-latest; post-call streaming hook flagging a generated chunk; borderline content newly caught after OpenAI updates moderation models or thresholds
Common situations: User-generated content apps surfacing the raw 400 to end users; test fixtures containing edgy text that trips categories; legitimate content (medical, security research) being over-flagged by category thresholds
Related errors
- Request blocked by Onyx Guard. Violations: {detection_messag
- guardrail_violation
- Content blocked: {category_name} conditional match '{matched
- Content blocked: {category_name} category keyword '{keyword}
- Content blocked: {pattern_name} pattern detected
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/596e5248157b573b.
Report an issue: GitHub.