{"record":{"id":"f4f664568eb98883","repo":"zylon-ai/private-gpt","slug":"no-valid-content-found-in-the-conversion-result","errorCode":null,"errorMessage":"No valid content found in the conversion result","messagePattern":"No valid content found in the conversion result","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/readers/docling/docling_api_reader.py","lineNumber":144,"sourceCode":"        self,\n        conversion_result: DoclingApiOutputModel,\n    ) -> list[str]:\n        def post_process_content(c: str) -> list[str]:\n            result = c\n\n            # Replace API image placeholder with a custom one\n            result = result.replace(DEFAULT_IMAGE_PLACEHOLDER, IMAGE_PLACEHOLDER)\n\n            # Split pages into contents\n            return result.split(PAGE_PLACEHOLDER)\n\n        content = (\n            conversion_result.document.md_content\n            or conversion_result.document.text_content\n            or conversion_result.document.html_content\n        )\n        if not content:\n            raise ValueError(\"No valid content found in the conversion result\")\n\n        return post_process_content(content)\n\n    async def lazy_load_data(\n        self,\n        file_info: FileInfo,\n        extra_info: dict[str, Any] | None = None,\n        execute_transformations: bool = True,\n        notification: NotifyProtocol | None = None,\n        *args: Any,\n        **load_kwargs: Any,\n    ) -> AsyncIterator[BaseNode]:\n        \"\"\"Lazy load file data into LlamaIndex Documents.\"\"\"\n        logger.debug(\"Starting Docling API parsing of file: %s\", file_info.file_name)\n\n        file_name = file_info.file_name or file_info.file_data.name\n        file_data = file_info.file_data\n        file_bytes = await asyncio.to_thread(file_data.read_bytes)","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/readers/docling/docling_api_reader.py#L126-L162","documentation":"Raised by DoclingApiReader._get_content when the conversion result's document payload has empty md_content, text_content, and html_content (all falsy after the `or` chain). The server reported a successful conversion, but none of the text representations contain anything, so there is nothing to split into pages or ingest. This is distinct from a transport failure — it is an 'empty output' data-quality failure.","triggerScenarios":"A successful/partial_success conversion of an image-only or scanned PDF with OCR disabled or OCR failing silently; a document whose pages contain only pictures/charts; a corrupt document that parses to zero pages; do_ocr=false on a scanned file. Raised per-file during lazy_load_data.","commonSituations":"Ingesting scanned PDFs into a Docling server built without OCR models; image-heavy decks exported to PDF; PDFs with text encoded in fonts Docling cannot map; partial_success where the only failed page was the sole content page.","solutions":["Enable OCR for the document/server (docling.use_ocr: true plus valid docling.langs) so scanned pages produce text.","Open the file locally and confirm it actually has extractable text (pdftotext file.pdf - ); if output is empty, the file is image-only.","If the file legitimately has no text, skip it in your ingestion pipeline instead of ingesting it.","Check the conversion_result.errors field path (status partial_success) — upstream code surfaces errors separately; enabling debug logging shows the raw result."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"async def has_extractable_text(path: str) -> bool:\n    # cheap local pre-check before sending to Docling\n    import pypdf\n    try:\n        reader = pypdf.PdfReader(path)\n        return any(page.extract_text().strip() for page in reader.pages)\n    except Exception:\n        return False  # cannot verify locally; let Docling decide\n\nif not await has_extractable_text(path) and not docling_cfg.use_ocr:\n    logger.warning(\"%s looks image-only but OCR is off\", path)","typeGuard":"def has_content(model) -> bool:\n    doc = model.document\n    return bool(doc.md_content or doc.text_content or doc.html_content)","tryCatchPattern":"try:\n    contents = reader._get_content(conversion_result)\nexcept ValueError as e:\n    if \"No valid content\" in str(e):\n        mark_for_ocr_or_skip(file_info)  # scanned doc or no-text doc\n    else:\n        raise","preventionTips":["Enable OCR (use_ocr + langs) when ingesting scanned archives.","Pre-screen image-only PDFs locally before spending server time on them."],"tags":["docling","empty-result","ocr","ingestion"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}