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, severity

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Read the 400 detail (category, keyword, severity) to identify which category file and keyword blocked the request.
  2. Edit the category YAML: remove the keyword, narrow it, or change its action/default_action away from BLOCK.
  3. Rephrase the input to drop the keyword when the block is legitimate.
  4. 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

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


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/0707fbf4c55f8193. Report an issue: GitHub.