deepset-ai/haystack · error · FileNotFoundError
File not found: {source}
Error message
File not found: {source} What it means
FileTypeRouter.run raises FileNotFoundError for a Path/str source that does not exist on disk when raise_on_failure=True was set at construction. Otherwise it only logs a warning and routes the file to the 'failed' output.
Source
Thrown at haystack/components/routers/file_type_router.py:166
If it's a list, its length must match the number of sources, as they are zipped together.
:returns: A dictionary where the keys are MIME types and the values are lists of data sources.
Two extra keys may be returned: `"unclassified"` when a source's MIME type doesn't match any pattern
and `"failed"` when a source cannot be processed (for example, a file path that doesn't exist).
:raises TypeError: If a source is not a Path, str, or ByteStream.
"""
mime_types: defaultdict[str, list[Path | ByteStream]] = defaultdict(list)
meta_list = normalize_metadata(meta=meta, sources_count=len(sources))
for source, meta_dict in zip(sources, meta_list, strict=True):
if isinstance(source, str):
source = Path(source)
if isinstance(source, Path):
if not source.exists():
if self._raise_on_failure:
raise FileNotFoundError(f"File not found: {source}")
logger.warning("File not found: {source}. Skipping it.", source=source)
mime_types["failed"].append(source)
continue
mime_type = _guess_mime_type(source)
elif isinstance(source, ByteStream):
mime_type = source.mime_type
else:
raise TypeError(f"Unsupported data source type: {type(source).__name__}")
# If we have metadata, we convert the source to ByteStream and add the metadata
if meta_dict:
try:
source = get_bytestream_from_source(source)
except Exception as e:
if self._raise_on_failure:
raise eView on GitHub (pinned to e318778c9b)
Solutions
- Check the path exists with Path(source).exists() before calling run
- Construct the router with raise_on_failure=False to skip missing files with a warning
- Fix the path (absolute path or correct working directory / volume mount)
Example fix
# before router = FileTypeRouter(mime_types=["application/pdf"], raise_on_failure=True) router.run(sources=["missing.pdf"]) # after from pathlib import Path existing = [s for s in ["missing.pdf"] if Path(s).exists()] router.run(sources=existing) # or set raise_on_failure=False
Defensive patterns
Strategy: type-guard
Validate before calling
from pathlib import Path missing = [s for s in sources if isinstance(s, (str, Path)) and not Path(s).exists()]
Type guard
def file_exists(source) -> bool:
from pathlib import Path
return isinstance(source, (str, Path)) and Path(source).exists() Try / catch
try:
result = router.run(sources=sources)
except FileNotFoundError as e:
logging.warning("Skipping missing file: %s", e)
sources = [s for s in sources if file_exists(s)]
result = router.run(sources=sources) Prevention
- Construct the router with raise_on_failure=False to skip missing files gracefully
- Resolve and normalize paths (absolute) before passing them
- Verify volume mounts / working directories in containerized runs
- Filter sources with Path.exists() before run
When it happens
Trigger: run(sources=[Path('/missing/file.pdf')]) on a router built with raise_on_failure=True.
Common situations: Files moved/deleted between pipeline steps; wrong mount paths in containers; relative paths resolved from an unexpected working directory.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Document with ID '{doc.id}' has an invalid file path '{resol
- Invalid template for condition: {condition_value}
- Invalid template for output: {output!r} (type: {type(output)
- Invalid template for output: {output}
- The list of mime types cannot be empty.
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/aadb23c41486bf79.
Report an issue: GitHub.