BerriAI/litellm · error · FileNotFoundError
Blocked words file not found: {file_path}
Error message
Blocked words file not found: {file_path} What it means
FileNotFoundError re-raised when open(file_path) fails while loading the blocked-words file — the configured path simply does not exist from the proxy process's point of view. The guardrail re-raises with the configured path in the message so you can see exactly what it tried to open.
Source
Thrown at litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py:810
data: Final = yaml.safe_load(f)
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(View on GitHub (pinned to 77b7c6c40c)
Solutions
- Use an absolute path for blocked_words_file in config.yaml.
- In Docker, mount or COPY the file into the image and reference the in-container absolute path.
- Verify existence as the proxy user: ls -l /path/to/blocked_words.yaml inside the container.
- Add a startup validation step that os.path.isfile()s every configured file before serving traffic.
Example fix
# before (relative — breaks when CWD differs) litellm_params: blocked_words_file: ./blocked_words.yaml # after (absolute, mounted into the container) litellm_params: blocked_words_file: /etc/litellm/blocked_words.yaml
Defensive patterns
Strategy: validation
Validate before calling
# Startup: every configured file path must exist (absolute paths preferred)
import os
def validate_file_paths(config: dict) -> list[str]:
missing = []
for g in config.get("litellm_settings", {}).get("guardrails", []):
fp = g.get("litellm_params", {}).get("blocked_words_file")
if fp and not os.path.isfile(fp):
missing.append(f"blocked_words_file not found: {fp} (cwd={os.getcwd()})")
return missing Prevention
- Use absolute paths in config — relative paths resolve against the proxy's CWD, which differs between dev and Docker.
- COPY or mount blocked-words files into the container and reference the in-container absolute path.
- Run the path validation above in a startup hook or CI check.
When it happens
Trigger: litellm_params.blocked_words_file contains a relative path that doesn't resolve from the proxy's CWD (common in Docker or installed-package deployments), an absolute path that isn't mounted into the container, or a typo'd/nonexistent file.
Common situations: Works locally (CWD = project root) then fails in Docker where the file was never COPY'd/mounted; relative path like ./config/blocked.yaml resolving differently in production; file renamed or moved.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- OpenAPI spec not found at {filepath}
- Content Filter: guardrail_name is required
- Category file path '{path}' is outside the allowed categorie
- Category file path '{path}' is outside the allowed categorie
- pattern_name is required for prebuilt patterns
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/aa5b3e6d867cc952.
Report an issue: GitHub.