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 e

View on GitHub (pinned to e318778c9b)

Solutions

  1. Check the path exists with Path(source).exists() before calling run
  2. Construct the router with raise_on_failure=False to skip missing files with a warning
  3. 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

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


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/aadb23c41486bf79. Report an issue: GitHub.