{"record":{"id":"4e79da480c08f5b7","repo":"ocrmypdf/OCRmyPDF","slug":"sidecar-filename-needed-when-output-file-is-not","errorCode":null,"errorMessage":"--sidecar filename needed when output file is not a path.","messagePattern":"--sidecar filename needed when output file is not a path\\.","errorType":"validation","errorClass":"BadArgsError","httpStatus":null,"severity":"error","filePath":"src/ocrmypdf/_validation.py","lineNumber":102,"sourceCode":"            \"\\n\"\n        )\n        raise MissingDependencyError(msg)\n\n\ndef check_options_sidecar(options: OcrOptions) -> None:\n    if options.sidecar == '\\0':\n        if options.output_file == '-':\n            raise BadArgsError(\"--sidecar filename needed when output file is stdout.\")\n        elif options.output_file == os.devnull:\n            raise BadArgsError(\n                \"--sidecar filename needed when output file is /dev/null or NUL.\"\n            )\n        elif not isinstance(options.output_file, str | Path):\n            # The '\\0' sentinel is only ever set by the CLI, which always\n            # supplies output_file as a plain path - not a stream. If this\n            # somehow fires, the caller mixed a CLI-only sentinel with the\n            # stream-based API.\n            raise BadArgsError(\n                \"--sidecar filename needed when output file is not a path.\"\n            )\n        options.sidecar = os.fspath(options.output_file) + '.txt'\n    if options.sidecar == options.input_file or options.sidecar == options.output_file:\n        raise BadArgsError(\n            \"--sidecar file must be different from the input and output files\"\n        )\n\n\ndef check_options_preprocessing(options: OcrOptions) -> None:\n    if options.clean_final:\n        options.clean = True\n    if options.unpaper_args and not options.clean:\n        raise BadArgsError(\"--clean is required for --unpaper-args\")\n    if (\n        options.rotate_pages_threshold != DEFAULT_ROTATE_PAGES_THRESHOLD\n        and not options.rotate_pages\n    ):","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/ocrmypdf/OCRmyPDF/blob/5074a0b0e109362422b768fd271ed84bf717c4ec/src/ocrmypdf/_validation.py#L84-L120","documentation":"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.","triggerScenarios":"Calling the Python API with sidecar='\\0' (a CLI-internal sentinel) while passing a stream object as output_file.","commonSituations":"API users copying CLI sentinel behavior; wrapping ocrmypdf in a service that writes to BytesIO.","solutions":["Pass an explicit sidecar path string when using the API","Or omit sidecar and let it default (only auto-derivation from a real path is supported)"],"exampleFix":"# before\nocrmypdf.ocr(BytesIO(pdf_bytes), BytesIO(), sidecar='\\0')\n# after\nsidecar = io.StringIO()\nocrmypdf.ocr(BytesIO(pdf_bytes), BytesIO(), sidecar=sidecar)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def is_valid_output(v) -> bool:\n    return isinstance(v, (str, Path)) or v in ('-', os.devnull)","tryCatchPattern":null,"preventionTips":["Never pass CLI sentinel values ('\\0') through the Python API; use real paths or streams"],"tags":["ocr","ocrmypdf","sidecar","python-api","type-mismatch"],"backgroundTag":"api-misuse","analyzedSha":"5074a0b0e109362422b768fd271ed84bf717c4ec","analyzedAt":"2026-08-27T11:57:38.523Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}