BerriAI/litellm · error · Exception

Error loading blocked words file {file_path}: {e}

Error message

Error loading blocked words file {file_path}: {e}

What it means

Generic Exception wrapping any non-FileNotFoundError failure while loading the blocked-words file. The wrapped cause (after the colon) is the real problem: yaml.YAMLError for malformed YAML syntax, PermissionError for unreadable files, ValueError from ContentFilterAction(...) for an invalid action value (only BLOCK/MASK-style enum members are accepted), or AttributeError when keyword is not a string and .lower() fails.

Source

Thrown at litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py:812

            if not isinstance(data, dict) or "blocked_words" not in data:
                raise ValueError("Invalid format: file must contain 'blocked_words' key with list of words")

            for word_data in data["blocked_words"]:
                if not isinstance(word_data, dict) or "keyword" not in word_data or "action" not in word_data:
                    verbose_proxy_logger.warning("Skipping invalid word entry: %s", word_data)
                    continue

                keyword = word_data["keyword"].lower()
                action = ContentFilterAction(word_data["action"])
                description = word_data.get("description")

                self.blocked_words[keyword] = (action, description)

            verbose_proxy_logger.info("Loaded %s blocked words from %s", len(data["blocked_words"]), file_path)
        except FileNotFoundError:
            raise FileNotFoundError(f"Blocked words file not found: {file_path}")
        except Exception as e:
            raise Exception(f"Error loading blocked words file {file_path}: {e}")

    def _find_pattern_spans(self, text: str, pattern_entry: CompiledPatternEntry) -> list[tuple[int, int]]:
        """Return all match spans for a pattern, applying contextual rules if required."""

        regex: Final[Pattern[str]] = pattern_entry["regex"]
        keyword_regex: Final[Pattern[str] | None] = pattern_entry.get("keyword_regex")
        allow_word_numbers: Final[bool] = pattern_entry.get("allow_word_numbers", False)

        keyword_matches: Final = list(keyword_regex.finditer(text)) if keyword_regex is not None else None
        if keyword_matches is not None and not keyword_matches:
            return []

        match_spans: Final[list[tuple[int, int]]] = []

        for match in regex.finditer(text):
            if keyword_matches is not None and not self._match_near_keyword(
                match.start(), match.end(), keyword_matches, text
            ):

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Read the exception text after the colon — it names the exact underlying error class and message.
  2. Validate the YAML parses: python -c "import yaml; yaml.safe_load(open('blocked_words.yaml'))".
  3. Make every action exactly a valid ContentFilterAction value (e.g. 'BLOCK', 'MASK') and every keyword a quoted string.
  4. Check file permissions so the proxy's runtime user can read the file.

Example fix

# before
blocked_words:
  - keyword: 42          # unquoted number -> .lower() fails
    action: block         # wrong value for the action enum

# after
blocked_words:
  - keyword: "42"
    action: BLOCK
Defensive patterns

Strategy: validation

Validate before calling

# Dry-run the full load: schema, enum actions, string keywords, permissions
import yaml
from litellm.types.proxy.guardrails.litellm_content_filter import ContentFilterAction

def dry_run_blocked_words(path: str) -> None:
    with open(path) as f:                      # raises PermissionError early
        data = yaml.safe_load(f)               # raises YAMLError early
    assert isinstance(data, dict) and "blocked_words" in data
    for w in data["blocked_words"]:
        assert isinstance(w["keyword"], str), f"keyword must be a string: {w}"
        ContentFilterAction(w["action"])      # raises ValueError for bad actions

Type guard

def blocked_words_entry_ok(entry: object) -> bool:
    """Narrow one parsed entry to the loadable shape (string keyword + valid action)."""
    if not isinstance(entry, dict):
        return False
    kw, act = entry.get("keyword"), entry.get("action")
    return isinstance(kw, str) and bool(kw) and isinstance(act, str) and act in ("BLOCK", "MASK")

Prevention

When it happens

Trigger: The blocked-words file exists and parses to a dict with blocked_words, but something inside fails: YAML syntax error (tabs, bad indentation), an action like 'block'/'censor' that is not a valid enum value, keyword as a number/None, or restrictive file permissions.

Common situations: Tabs instead of spaces in hand-edited YAML; lowercase action values copied from docs of other tools; a keyword field containing a number (e.g. 42) instead of a quoted string; file owned by root while the proxy runs as a non-root user.

Related errors


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