BerriAI/litellm · error · HTTPException
Content blocked: {category_name} category keyword '{keyword}
Error message
Content blocked: {category_name} category keyword '{keyword}' detected (severity: {severity}) What it means
HTTPException(400) raised by _handle_category_keyword_match when a category keyword match resolves to action BLOCK. Category files define keywords with a default_action (or per-keyword action) and a severity; when a listed keyword appears in the text and the action is BLOCK, the whole request is rejected with category, keyword, and severity in the detail payload.
Source
Thrown at litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py:1267
action: ContentFilterAction,
text: str,
detections: list[ContentFilterDetection] | None,
) -> str:
"""Handle category keyword match detection and action."""
if detections is not None:
category_detection: Final[CategoryKeywordDetection] = {
"type": "category_keyword",
"category": category_name,
"keyword": keyword,
"severity": severity,
"action": action.value,
}
detections.append(category_detection)
if action == ContentFilterAction.BLOCK:
error_msg = f"Content blocked: {category_name} category keyword '{keyword}' detected (severity: {severity})"
verbose_proxy_logger.warning(error_msg)
raise HTTPException(
status_code=400,
detail={
"error": error_msg,
"category": category_name,
"keyword": keyword,
"severity": severity,
},
)
elif action == ContentFilterAction.MASK:
keyword_pattern_for_masking: Final = self._keyword_to_regex_pattern(keyword)
text = re.sub(
keyword_pattern_for_masking,
self.keyword_redaction_tag,
text,
flags=re.IGNORECASE,
)
verbose_proxy_logger.info(
"Masked category keyword '%s' from %s (severity: %s)", keyword, category_name, severityView on GitHub (pinned to 77b7c6c40c)
Solutions
- Read the 400 detail (category, keyword, severity) to identify which category file and keyword blocked the request.
- Edit the category YAML: remove the keyword, narrow it, or change its action/default_action away from BLOCK.
- Rephrase the input to drop the keyword when the block is legitimate.
- Handle the 400 gracefully in the client — it is deterministic for the same input, so retries will not help.
Defensive patterns
Strategy: try-catch
Try / catch
from fastapi import HTTPException
def is_category_keyword_block(exc: HTTPException) -> bool:
d = exc.detail if isinstance(exc.detail, dict) else {}
return (
exc.status_code == 400
and "category keyword" in str(d.get("error", ""))
)
try:
resp = await client.chat.completions.create(**params)
except HTTPException as e:
if is_category_keyword_block(e):
# d['category'], d['keyword'], d['severity'] identify the exact rule
raise PolicyRejectedError("Request blocked by content policy") from e
raise Prevention
- Audit enabled category files: broad keywords block benign traffic — narrow or remove them.
- Change a category's default_action or per-keyword action if BLOCK is too strict for your users.
- Keep severity_threshold tuned so low-severity keywords log instead of block.
- Never auto-retry a policy 400; surface a friendly message and audit the detail.
When it happens
Trigger: A guarded request's text contains a keyword listed in an enabled category file (e.g. a weapons or self-harm category), and that match's action — explicit or the category's default_action — is BLOCK.
Common situations: Shipped policy templates enabling strict categories by default; benign traffic tripping overly broad keywords (substring-like matches); a security/compliance team tightening categories without a staging pass.
Related errors
- Content blocked: {category_name} conditional match '{matched
- Content blocked: {pattern_name} pattern detected
- Content blocked: keyword '{keyword}' detected
- guardrail_violation
- Violated CrowdStrike AIDR guardrail policy
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/0707fbf4c55f8193.
Report an issue: GitHub.