crewAIInc/crewAI · error · ValueError
Blocked unsafe URL: {e}
Error message
Blocked unsafe URL: {e} What it means
Raised in RAGTool.add()'s per-argument loop when a value parses as a URL (urlparse yields a scheme of http, https, or file) and validate_url rejects it. Only urlparse-specific parse errors are caught silently; the guard's own ValueError always propagates, wrapped as 'Blocked unsafe URL: <reason>', so a security rejection can never be silently bypassed.
Source
Thrown at lib/crewai-tools/src/crewai_tools/tools/rag/rag_tool.py:315
for arg in args:
source_ref = (
str(arg.get("source", arg.get("content", "")))
if isinstance(arg, dict)
else str(arg)
)
# Check if it's a URL — only catch urlparse-specific errors here;
# validate_url's ValueError must propagate so it is never silently bypassed.
try:
parsed = urlparse(source_ref)
except (ValueError, AttributeError):
parsed = None
if parsed is not None and parsed.scheme in ("http", "https", "file"):
try:
validate_url(source_ref)
except ValueError as e:
raise ValueError(f"Blocked unsafe URL: {e}") from e
validated_args.append(arg)
continue
# Check if it looks like a file path (not a plain text string).
# Check both os.sep (backslash on Windows) and "/" so that
# forward-slash paths like "sub/file.txt" are caught on all platforms.
if (
os.path.sep in source_ref
or "/" in source_ref
or source_ref.startswith(".")
or os.path.isabs(source_ref)
):
try:
resolved_ref = validate_file_path(source_ref)
except ValueError as e:
raise ValueError(f"Blocked unsafe file path: {e}") from e
# Use the resolved path to prevent symlink TOCTOU
if isinstance(arg, dict):View on GitHub (pinned to 754d7323be)
Solutions
- For local files, pass the filesystem path ('./docs/x.pdf') instead of a file:// URL — the path branch validates it separately
- For blocked http(s) hosts, fetch the content from an allowed context and add it as text content
- Read the embedded validate_url reason to see the exact rule tripped
- Keep agent-facing prompts away from internal hostnames to avoid repeated guard hits
Example fix
# before
rag_tool.add('file:///home/user/report.pdf') # ValueError: Blocked unsafe URL
# after
rag_tool.add('/home/user/report.pdf') # handled by path validation, PDF auto-detected
Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
from crewai_tools.security.safe_path import validate_url
def addable_url(u: str) -> bool:
try:
parsed = urlparse(u)
except ValueError:
return False
if parsed.scheme in ("http", "https", "file"):
try:
validate_url(u)
return True
except ValueError:
return False
return False Try / catch
try:
rag_tool.add(source_ref)
except ValueError as e:
if "Blocked unsafe URL" in str(e):
# local file? switch to a filesystem path so the path branch handles it
if source_ref.startswith("file://"):
rag_tool.add(source_ref[len("file://"):])
else:
raise
else:
raise Prevention
- Use filesystem paths, not file:// URLs, for local documents
- Pre-check http(s) URLs with validate_url to get the rejection reason early
- Keep agent prompts scoped to public web URLs
- Log blocked URLs to spot agents probing internal endpoints
When it happens
Trigger: rag_tool.add('http://127.0.0.1:8080/health') or file:// URLs pointing at local files — anything whose scheme marks it a URL and whose host/scheme the SSRF guard blocks (loopback, private IP, metadata endpoints, file scheme).
Common situations: Trying to ingest file:// URLs for local documents (blocked — use a filesystem path instead); agents probing internal HTTP services during research tasks; localhost dev URLs in examples that work in docs but are blocked by the guard.
Related errors
- Blocked unsafe {label}: {e}
- file:// URLs are not allowed: '{url}'. Use a file path inste
- URL scheme '{parsed.scheme}' is not allowed. Only http and h
- URL has no hostname: '{url}'
- URL '{url}' resolves to private/reserved IP {ip_str}. Access
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/82363ae8643044bc.
Report an issue: GitHub.