ocrmypdf/OCRmyPDF · error · BadArgsError

--sidecar filename needed when output file is not a path.

Error message

--sidecar filename needed when output file is not a path.

What it means

Defensive check: the '\0' sidecar sentinel is only produced by the CLI, which always supplies output_file as a path. If output_file is not a str/Path (e.g. a file stream passed via the Python API), the caller mixed the CLI sentinel with the stream API.

Source

Thrown at src/ocrmypdf/_validation.py:102

            "\n"
        )
        raise MissingDependencyError(msg)


def check_options_sidecar(options: OcrOptions) -> None:
    if options.sidecar == '\0':
        if options.output_file == '-':
            raise BadArgsError("--sidecar filename needed when output file is stdout.")
        elif options.output_file == os.devnull:
            raise BadArgsError(
                "--sidecar filename needed when output file is /dev/null or NUL."
            )
        elif not isinstance(options.output_file, str | Path):
            # The '\0' sentinel is only ever set by the CLI, which always
            # supplies output_file as a plain path - not a stream. If this
            # somehow fires, the caller mixed a CLI-only sentinel with the
            # stream-based API.
            raise BadArgsError(
                "--sidecar filename needed when output file is not a path."
            )
        options.sidecar = os.fspath(options.output_file) + '.txt'
    if options.sidecar == options.input_file or options.sidecar == options.output_file:
        raise BadArgsError(
            "--sidecar file must be different from the input and output files"
        )


def check_options_preprocessing(options: OcrOptions) -> None:
    if options.clean_final:
        options.clean = True
    if options.unpaper_args and not options.clean:
        raise BadArgsError("--clean is required for --unpaper-args")
    if (
        options.rotate_pages_threshold != DEFAULT_ROTATE_PAGES_THRESHOLD
        and not options.rotate_pages
    ):

View on GitHub (pinned to 5074a0b0e1)

Solutions

  1. Pass an explicit sidecar path string when using the API
  2. Or omit sidecar and let it default (only auto-derivation from a real path is supported)

Example fix

# before
ocrmypdf.ocr(BytesIO(pdf_bytes), BytesIO(), sidecar='\0')
# after
sidecar = io.StringIO()
ocrmypdf.ocr(BytesIO(pdf_bytes), BytesIO(), sidecar=sidecar)
Defensive patterns

Strategy: type-guard

Type guard

def is_valid_output(v) -> bool:
    return isinstance(v, (str, Path)) or v in ('-', os.devnull)

Prevention

When it happens

Trigger: Calling the Python API with sidecar='\0' (a CLI-internal sentinel) while passing a stream object as output_file.

Common situations: API users copying CLI sentinel behavior; wrapping ocrmypdf in a service that writes to BytesIO.

Related errors


AI-assisted analysis of ocrmypdf/OCRmyPDF@5074a0b0e1 (2026-08-27). Data as JSON: /api/errors/4e79da480c08f5b7. Report an issue: GitHub.