cocoindex-io/cocoindex · error · ValueError
Path is not a directory
Error message
Path is not a directory: {root_resolved} What it means
localfs directory walking resolves the root path and requires it to be an existing directory. If the resolved root is not a directory (missing path, a file, or a broken symlink), _walk_sync raises ValueError before yielding any File objects. The error surfaces when iterating the DirSource (via __aiter__).
Solutions
- Fix the root path to point to an existing directory
- Create the directory if it is expected to exist (mkdir -p) before running the pipeline
- If the path is supposed to be a file source, use the appropriate file-based API instead of a directory walk
- Make the path absolute (pathlib.Path(...).resolve()) and verify is_dir() before wiring it into the source
Example fix
// before
source = localfs.walk_dir("./documets") # typo -> not a directory
// after
root = pathlib.Path("./documents").resolve()
assert root.is_dir(), root
source = localfs.walk_dir(root, recursive=True, path_matcher=PatternFilePathMatcher(["**/*.md"])) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
root = Path(path).resolve()
if not root.is_dir():
raise NotADirectoryError(f"source root is not a directory: {root}") Type guard
def is_existing_dir(p) -> bool:
from pathlib import Path
try:
return Path(p).resolve().is_dir()
except OSError:
return False Try / catch
try:
async for f in source:
...
except ValueError as e:
if str(e).startswith("Path is not a directory"):
logger.error("fix --sourcedir: %s", e)
sys.exit(2)
raise Prevention
- Resolve relative paths against an explicit base directory, not the ambient cwd
- Check the path exists and is a directory at app startup (fail fast in main)
- Use absolute paths in config files and CI env vars
- Verify the directory survives until the run finishes (mount points, tmpdirs)
When it happens
Trigger: Creating localfs.dir(...) / DirSource with a root path that does not exist, points to a regular file, or is a dangling symlink, then iterating it (async for ... in source, or walk_dir items consumed by mount_each).
Common situations: Typo in the source directory path; pointing the pipeline at a file instead of a directory; the directory was deleted/moved before the run; relative path resolved from an unexpected working directory (e.g. different cwd in CI).
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/2271236453c949df.
Report an issue: GitHub.
Appendix: source
Thrown at python/cocoindex/connectors/localfs/_source.py:110
path: FilePath | Path | ContextKey[Path],
*,
live: bool = False,
recursive: bool = False,
path_matcher: FilePathMatcher | None = None,
rescan_interval: datetime.timedelta | None = _DEFAULT_RESCAN_INTERVAL,
) -> None:
self._root_path = to_file_path(path)
self._live = live
self._recursive = recursive
self._path_matcher = path_matcher or MatchAllFilePathMatcher()
self._rescan_interval = rescan_interval
def _walk_sync(self) -> Iterator[File]:
"""Synchronously walk the directory and yield File objects (internal helper)."""
root_resolved = self._root_path.resolve()
if not root_resolved.is_dir():
raise ValueError(f"Path is not a directory: {root_resolved}")
dirs_to_process: list[Path] = [root_resolved]
while dirs_to_process:
current_dir = dirs_to_process.pop()
try:
entries = list(current_dir.iterdir())
except PermissionError:
continue
subdirs: list[Path] = []
for entry in entries:
try:
relative_path = entry.relative_to(root_resolved)
except ValueError:
# Should not happen, but skip if it doesView on GitHub (pinned to e84aa99b32)