BerriAI/litellm · error · ValueError
Category file path '{path}' is outside the allowed categorie
Error message
Category file path '{path}' is outside the allowed categories directory What it means
ValueError from ContentFilterGuardrail._assert_within_categories_dir raised when os.path.commonpath() itself throws — which happens on Windows when the resolved category file path and the guardrail module directory live on different drives (e.g. D:\policies\cat.yaml vs C:\...\site-packages\litellm). Containment cannot even be computed across drives, so the jail rejects the path. Note the message omits the directory because commonpath failed before the comparison.
Source
Thrown at litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py:353
@staticmethod
def _category_config_view(cat_config: ContentFilterCategoryConfig) -> _CategoryConfigView:
return {
"category": cat_config.get("category"),
"enabled": cat_config.get("enabled", True),
"action": cat_config.get("action"),
"category_file": cat_config.get("category_file"),
}
@staticmethod
def _assert_within_categories_dir(path: str, categories_dir: str) -> None:
"""Raise ValueError if path escapes the categories directory."""
resolved: Final = os.path.realpath(path)
allowed: Final = os.path.realpath(categories_dir)
try:
common: Final = os.path.commonpath([resolved, allowed])
except ValueError:
# commonpath() raises ValueError on Windows when paths span different drives
raise ValueError(f"Category file path '{path}' is outside the allowed categories directory")
if common != allowed:
raise ValueError(
f"Category file path '{path}' is outside the allowed categories directory '{categories_dir}'"
)
def _resolve_category_file_path(self, file_path: str) -> str:
"""
Resolve a category file path that may be relative.
Paths in policy templates (e.g. category_file) are often stored as
relative paths like "litellm/proxy/.../policy_templates/file.yaml".
These only work when the CWD is the project root. In production
(Docker, installed packages, etc.) the CWD is different, so the
file isn't found.
Resolution order:
1. Return as-is if absolute or already exists (jailed to module dir).
2. Try joining the full path relative to this module's directory (jailed).View on GitHub (pinned to 77b7c6c40c)
Solutions
- Move the category YAML files onto the same drive as the litellm installation, under the litellm_content_filter module directory.
- Use a relative category_file path that resolves inside the module directory (the resolver jails those safely).
- If the files must stay outside the package on a trusted host, set LITELLM_CONTENT_FILTER_ALLOW_EXTERNAL_PATHS=true to disable the directory jail.
- Prefer running the proxy in the official Docker image (Linux) where cross-drive paths cannot occur.
Example fix
# before (Windows, cross-drive) policy_template: category_file: 'D:\policies\pii.yaml' # after — file relocated inside the module dir, relative path category_file: 'policy_templates/pii.yaml'
Defensive patterns
Strategy: validation
Validate before calling
# Startup check: a category path must be comparable with the module dir (same drive on Windows)
import os
def category_path_comparable(path: str, module_dir: str) -> bool:
try:
os.path.commonpath([os.path.realpath(path), os.path.realpath(module_dir)])
return True
except ValueError:
return False # cross-drive (Windows) — will be rejected by the jail
# if not category_path_comparable(cfg_path, os.path.dirname(litellm_content_filter.__file__)): fix or relocate Prevention
- On Windows, keep category files on the same drive as the litellm package directory.
- Prefer relative category_file paths that resolve inside the module dir — the resolver jails them safely.
- Consider the official Linux Docker image for production to sidestep drive-letter path semantics entirely.
- Reserve LITELLM_CONTENT_FILTER_ALLOW_EXTERNAL_PATHS=true for trusted hosts where the config source is controlled.
When it happens
Trigger: Running the proxy on Windows (or a Windows CI runner) with a category_file value that resolves to an absolute path on a different drive than the litellm package directory, while LITELLM_CONTENT_FILTER_ALLOW_EXTERNAL_PATHS is not set.
Common situations: Windows deployments or tests that pass absolute category paths from another drive; drive-relative or cross-drive configs copied from Linux examples that used /-style paths.
Related errors
- Category file path '{path}' is outside the allowed categorie
- Blocked words file not found: {file_path}
- Failed to load prompt '{prompt_id}' from BitBucket: {e}
- Prompt directory does not exist: {self.prompt_directory}
- {custom_llm_provider.capitalize()}Exception ContentPolicyVio
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/21e4a589705de922.
Report an issue: GitHub.