crewAIInc/crewAI · error · ValueError
Source must be a valid file path or URL, got: {source_conten
Error message
Source must be a valid file path or URL, got: {source_content.source} What it means
Raised by DOCXLoader.load() when the source is neither recognized as a URL nor an existing local path. The loader branches on source_content.is_url() then source_content.path_exists(); the else branch rejects anything else — sources that are neither an http(s) URL nor a file present on disk.
Source
Thrown at lib/crewai-tools/src/crewai_tools/rag/loaders/docx_loader.py:30
try:
from docx import Document as DocxDocument
except ImportError as e:
raise ImportError(
"python-docx is required for DOCX loading. Install with: 'uv pip install python-docx' or pip install crewai-tools[rag]"
) from e
source_ref = source_content.source_ref
if source_content.is_url():
temp_file = self._download_from_url(source_ref, kwargs)
try:
return self._load_from_file(temp_file, source_ref, DocxDocument)
finally:
os.unlink(temp_file)
elif source_content.path_exists():
return self._load_from_file(source_ref, source_ref, DocxDocument)
else:
raise ValueError(
f"Source must be a valid file path or URL, got: {source_content.source}"
)
@staticmethod
def _download_from_url(url: str, kwargs: dict[str, Any]) -> str:
headers = kwargs.get(
"headers",
{
"Accept": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"User-Agent": "Mozilla/5.0 (compatible; crewai-tools DOCXLoader)",
},
)
try:
response = safe_get(url, headers=headers, timeout=30)
response.raise_for_status()
# Create temporary file to save the DOCX contentView on GitHub (pinned to 754d7323be)
Solutions
- Normalize the source first: expand ~ and env vars, make relative paths absolute against a known base, and prefix URLs with https://.
- Verify existence with Path(source).expanduser().resolve().exists() before calling load; if it is a remote URI scheme like s3://, download the file first.
- For remote storage, sync the object to a temp file and pass the local path or a public https URL.
Example fix
# before
result = DOCXLoader().load(SourceContent('~/reports/spec.docx')) # literal ~ not expanded
# after
from pathlib import Path
src = str(Path('~/reports/spec.docx').expanduser().resolve())
assert Path(src).is_file(), src
result = DOCXLoader().load(SourceContent(src)) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path\n\ndef normalize_source(s: str) -> str:\n s = Path(s).expanduser()\n if s.suffix or '/' in str(s):\n return str(s.resolve()) if s.exists() else ('https://' + s if '.' in s else s)\n return str(s) Type guard
from pathlib import Path\n\ndef is_loadable_docx_source(s: str) -> bool:\n return s.startswith(('http://', 'https://')) or Path(s).expanduser().is_file() Try / catch
try:\n result = DOCXLoader().load(source)\nexcept ValueError as e:\n if 'must be a valid file path or URL' in str(e):\n raise FileNotFoundError(source.source) from e\n raise
Prevention
- Expand ~ and env vars before building sources.
- Reject unknown URI schemes early (s3://, gs:// need download first).
- Log the exact source string on failure to catch invisible whitespace.
When it happens
Trigger: Passing a bare filename that does not exist in the current working directory; a malformed URL missing the scheme (example.com/file.docx); a Windows UNC or path with unexpanded variables; an empty or whitespace-only source string; a file path with a typo.
Common situations: Relative paths evaluated from an unexpected cwd (notebooks, launched services); URLs pasted without https://; paths built from untrusted or unvalidated user input; files that were deleted between listing and loading; S3/gs:// URIs that this local/URL-only loader does not support.
Related errors
- Directory does not exist: {source_ref}
- Path is not a directory: {source_ref}
- PDF file not found: {file_path}
- File not found: {self.path}
- Path is not a file: {self.path}
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/8617b1aba94d2ea9.
Report an issue: GitHub.