docling-project/docling · error · ValueError

Invalid filename: contains null byte.

Error message

Invalid filename: contains null byte.

What it means

Filenames handed to the Tesseract CLI (e.g. input images and output bases) are sanitized before subprocess invocation. A filename containing a NUL byte raises this ValueError, mirroring the path and command sanitizers, since NUL bytes cannot occur in valid filenames and signal malformed or injected input.

Source

Thrown at docling/models/stages/ocr/tesseract_ocr_cli_model.py:132

    @staticmethod
    def _sanitize_cmd(cmd: str) -> str:
        """Validate and sanitize the Tesseract executable name/path to prevent injection.

        Rejects values containing null bytes.
        """
        if "\x00" in cmd:
            raise ValueError("Invalid Tesseract command: contains null byte.")
        return cmd

    @staticmethod
    def _sanitize_filename(filename: str) -> str:
        """Validate and sanitize a filename passed to the Tesseract CLI.

        Rejects paths containing null bytes and resolves to an absolute path.
        """
        if "\x00" in filename:
            raise ValueError("Invalid filename: contains null byte.")
        return str(Path(filename).resolve())

    def _get_name_and_version(self) -> Tuple[str, str]:
        if self._name is not None and self._version is not None:
            return self._name, self._version  # type: ignore

        cmd = [self._safe_tesseract_cmd, "--version"]

        proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=False)
        stdout, stderr = proc.communicate()

        proc.wait()

        # HACK: Windows versions of Tesseract output the version to stdout, Linux versions
        # to stderr, so check both.
        version_line = (
            (stdout.decode("utf8").strip() or stderr.decode("utf8").strip())
            .split("\n")[0]

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Clean or drop the offending path; strip control characters from file lists before processing.
  2. Validate external path sources (manifests, uploads) with a null-byte check up front.
  3. Log repr(path) for failed batches to identify the corrupted entry quickly.

Example fix

# before
paths = ["page1.png\x00", "page2.png"]

# after
paths = [p for p in raw_paths if "\x00" not in p]
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def safe_filenames(paths: list[str]) -> list[str]:
    bad = [p for p in paths if "\x00" in p]
    if bad:
        raise ValueError(f"filenames contain NUL bytes: {bad!r}")
    return [str(Path(p).resolve()) for p in paths]

Type guard

def is_nul_free_filename(p: str) -> bool:
    return bool(p) and "\x00" not in p

Try / catch

try:
    model.run_batch(files)
except ValueError as e:
    if "Invalid filename" in str(e):
        files = [f for f in files if is_nul_free_filename(f)]
        model.run_batch(files)
    else:
        raise

Prevention

When it happens

Trigger: Any flow that passes a filename containing \x00 to the CLI-based Tesseract model — e.g. processing a list of files where one path came from binary or corrupted metadata.

Common situations: Batch processing paths read from untrusted manifests, archives with malformed entry names, or strings decoded from binary blobs.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/0a053c79ababc19b. Report an issue: GitHub.