crewAIInc/crewAI · error · ValueError
Path is not a directory: {source_ref}
Error message
Path is not a directory: {source_ref} What it means
Raised by DirectoryLoader.load() when the source_ref exists on disk but is not a directory (os.path.isdir fails). This catches the case where a regular file, symlink to a file, or special file is passed where a directory tree is expected. The message distinguishes it from the not-found case so the caller knows the path resolves but to the wrong kind of object.
Source
Thrown at lib/crewai-tools/src/crewai_tools/rag/loaders/directory_loader.py:32
source_content: Directory path or URL to a directory listing
**kwargs: Additional options:
- recursive: bool (default True) - Whether to search recursively
- include_extensions: list - Only include files with these extensions
- exclude_extensions: list - Exclude files with these extensions
- max_files: int - Maximum number of files to process
"""
source_ref = source_content.source_ref
if source_content.is_url():
raise ValueError(
"URL directory loading is not supported. Please provide a local directory path."
)
if not os.path.exists(source_ref):
raise FileNotFoundError(f"Directory does not exist: {source_ref}")
if not os.path.isdir(source_ref):
raise ValueError(f"Path is not a directory: {source_ref}")
return self._process_directory(source_ref, kwargs)
def _process_directory(self, dir_path: str, kwargs: dict[str, Any]) -> LoaderResult:
recursive: bool = kwargs.get("recursive", True)
include_extensions: list[str] | None = kwargs.get("include_extensions", None)
exclude_extensions: list[str] | None = kwargs.get("exclude_extensions", None)
max_files: int | None = kwargs.get("max_files", None)
files = self._find_files(
dir_path, recursive, include_extensions, exclude_extensions
)
if max_files is not None and len(files) > max_files:
files = files[:max_files]
all_contents = []
processed_files = []View on GitHub (pinned to 754d7323be)
Solutions
- If you meant to load one file, use the matching file loader (TextLoader, PDFLoader, DOCXLoader) or point DirectoryLoader at the containing directory.
- If you meant a directory, correct the path so it names the folder, not a file inside it.
- Add a pre-check with os.path.isdir(source) and fail with your own clearer message.
Example fix
# before
result = DirectoryLoader().load(SourceContent('reports/q3.pdf'))
# after
result = PDFLoader().load(SourceContent('reports/q3.pdf'))
# or, to ingest the whole folder:
result = DirectoryLoader().load(SourceContent('reports')) Defensive patterns
Strategy: type-guard
Validate before calling
import os\n\ndef ensure_directory(path: str) -> bool:\n return os.path.isdir(path) and not os.path.isfile(path)
Type guard
def is_directory_source(s: str) -> bool:\n return os.path.isdir(s)
Try / catch
try:\n result = loader.load(source)\nexcept ValueError as e:\n if 'not a directory' in str(e):\n # route single files to a file loader\n result = pick_file_loader(s).load(source)\n else:\n raise
Prevention
- Choose the loader by source kind, not convenience.
- Route files to file loaders; keep DirectoryLoader for folders.
- Check symlinks with os.path.realpath before deciding.
When it happens
Trigger: Passing a path to a single file (e.g. notes.txt) to DirectoryLoader instead of a file loader like TextLoader or PDFLoader; passing a symlink that points to a file; passing a device/socket path.
Common situations: Copy-paste from a file-loader example into DirectoryLoader; user-supplied source strings where a filename is given where a folder is expected; broken symlinks that resolve to files; picking DirectoryLoader from the loader registry because it accepts any 'source'.
Related errors
- Directory does not exist: {source_ref}
- URL directory loading is not supported. Please provide a loc
- Source must be a valid file path or URL, got: {source_conten
- Invalid GitHub URL: {repo_url}
- Invalid GitHub repository URL: {repo_url}
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/7080497b8e8ff2fe.
Report an issue: GitHub.