diff --git a/integrations/docling_serve/src/haystack_integrations/components/converters/docling_serve/converter.py b/integrations/docling_serve/src/haystack_integrations/components/converters/docling_serve/converter.py index 31bbbf8c40..664e1fc0ce 100644 --- a/integrations/docling_serve/src/haystack_integrations/components/converters/docling_serve/converter.py +++ b/integrations/docling_serve/src/haystack_integrations/components/converters/docling_serve/converter.py @@ -518,6 +518,12 @@ def run( documents.append(Document(content=content, meta=merged_meta)) else: logger.warning("No content returned for source {source}.", source=source) + except (OSError, TypeError) as e: + logger.warning( + "Could not read local source {source}. Skipping it. Error: {error}", + source=source, + error=e, + ) except httpx.HTTPStatusError as e: logger.warning( "DoclingServe returned HTTP {status} for {source}: {body}", @@ -592,6 +598,12 @@ async def run_async( documents.append(Document(content=content, meta=merged_meta)) else: logger.warning("No content returned for source {source}.", source=source) + except (OSError, TypeError) as e: + logger.warning( + "Could not read local source {source}. Skipping it. Error: {error}", + source=source, + error=e, + ) except httpx.HTTPStatusError as e: logger.warning( "DoclingServe returned HTTP {status} for {source}: {body}", diff --git a/integrations/docling_serve/tests/test_converter.py b/integrations/docling_serve/tests/test_converter.py index 0c530746cb..ec4b7845cf 100644 --- a/integrations/docling_serve/tests/test_converter.py +++ b/integrations/docling_serve/tests/test_converter.py @@ -325,6 +325,21 @@ def test_run_skips_failed_sync_file_response_details(self, tmp_path, caplog): assert result["documents"] == [] assert "file conversion failed" in caplog.text + def test_run_skips_missing_local_file(self, tmp_path, caplog): + missing = tmp_path / "missing.pdf" + good = tmp_path / "good.pdf" + good.write_bytes(b"%PDF-test") + converter = DoclingServeConverter(api_key=None) + mock_resp = _mock_httpx_response("# Good content") + + with patch("httpx.Client.post", return_value=mock_resp): + with caplog.at_level(logging.WARNING): + result = converter.run(sources=[missing, good]) + + assert len(result["documents"]) == 1 + assert result["documents"][0].content == "# Good content" + assert "Could not read local source" in caplog.text + def test_run_text_export(self): converter = DoclingServeConverter(export_type=ExportType.TEXT, api_key=None) mock_resp = _mock_httpx_response("plain text content", ExportType.TEXT) @@ -604,6 +619,26 @@ async def test_run_async_skips_on_connection_error(self, caplog): assert result["documents"] == [] assert "Could not connect" in caplog.text + @pytest.mark.asyncio + async def test_run_async_skips_missing_local_file(self, tmp_path, caplog): + missing = tmp_path / "missing.pdf" + good = tmp_path / "good.pdf" + good.write_bytes(b"%PDF-test") + converter = DoclingServeConverter(api_key=None) + mock_resp = httpx.Response( + 200, + json={"document": {"md_content": "# Good content"}, "status": "success"}, + request=httpx.Request("POST", "http://test"), + ) + + with patch("httpx.AsyncClient.post", new_callable=AsyncMock, return_value=mock_resp): + with caplog.at_level(logging.WARNING): + result = await converter.run_async(sources=[missing, good]) + + assert len(result["documents"]) == 1 + assert result["documents"][0].content == "# Good content" + assert "Could not read local source" in caplog.text + @pytest.mark.asyncio async def test_run_async_multiple_sources(self): converter = DoclingServeConverter(api_key=None)