zylon-ai/private-gpt · error · ValueError

Document conversion failed: {e}

Error message

Document conversion failed: {e}

What it means

Raised by DoclingApiReader.lazy_load_data when the underlying client.convert_from_bytes call throws any exception — the reader wraps it in ValueError with 'Document conversion failed: {original}' and chains the cause. The original exception can be an aiohttp error that already survived the client's retry decorators (5 tries with jitter on connection errors and timeouts), an HTTP 4xx/5xx from raise_for_status, or a payload/model error.

Source

Thrown at private_gpt/components/readers/docling/docling_api_reader.py:170

        execute_transformations: bool = True,
        notification: NotifyProtocol | None = None,
        *args: Any,
        **load_kwargs: Any,
    ) -> AsyncIterator[BaseNode]:
        """Lazy load file data into LlamaIndex Documents."""
        logger.debug("Starting Docling API parsing of file: %s", file_info.file_name)

        file_name = file_info.file_name or file_info.file_data.name
        file_data = file_info.file_data
        file_bytes = await asyncio.to_thread(file_data.read_bytes)
        pages = file_info.config.get("pages", None)

        try:
            conversion_result = await self.client.convert_from_bytes(
                file_name, file_bytes, to_formats=["md"], pages=pages, **load_kwargs
            )
        except Exception as e:
            raise ValueError(f"Document conversion failed: {e}") from e

        if conversion_result.status not in ["success", "partial_success"]:
            raise ValueError(
                f"Document conversion failed with status: {conversion_result.status}. "
                f"Errors: {conversion_result.errors}"
            )

        contents = self._get_content(conversion_result)
        valid_contents = [content for content in contents if content]
        if not valid_contents:
            raise ValueError("No valid document content found after conversion")
        if self._is_extraction_unsuccessful(valid_contents):
            raise ExtractionUnsuccessfulError(
                f"Document extraction unsuccessful for '{file_name}': unmapped-glyph "
                f"ratio exceeded threshold ({self.config.failure_threshold})."
            )

        docs = [

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Read the chained cause (`e.__cause__`) — the fix depends entirely on the wrapped exception; for ClientConnectorError verify the server is up and docling.api_base is correct.
  2. Curl the server directly: curl -X POST {api_base}/v1alpha/convert/source with a small file to confirm reachability and auth.
  3. For HTTP errors, match the status: 401/403 → set docling.api_key/tenant_id; 413 → shrink file or raise proxy limits; 422 → options mismatch with server version.
  4. For response-shape errors (ValidationError), check that docling.api_version ('v1alpha' vs 'v1') matches your Docling server release.
  5. Catch this at the ingestion layer and quarantine the file rather than aborting the whole batch.

Example fix

# before
try:
    conversion_result = await self.client.convert_from_bytes(...)
except Exception as e:
    raise ValueError(f"Document conversion failed: {e}") from e

# caller-side handling
try:
    docs = await reader.lazy_load_data(file_info)
except ValueError as e:
    if str(e).startswith("Document conversion failed") and e.__cause__:
        logger.error("cause: %r", e.__cause__)
    raise
Defensive patterns

Strategy: try-catch

Validate before calling

async def docling_reachable(api_base: str, api_key: str | None = None) -> bool:
    import aiohttp
    headers = {"X-Api-Key": api_key} if api_key else {}
    try:
        async with aiohttp.ClientSession() as s, s.get(f"{api_base}", headers=headers, timeout=aiohttp.ClientTimeout(total=5)) as r:
            return r.status < 500
    except aiohttp.ClientError:
        return False

Try / catch

try:
    nodes = [n async for n in reader.lazy_load_data(file_info)]
except ValueError as e:
    if str(e).startswith("Document conversion failed:"):
        cause = e.__cause__
        if isinstance(cause, (aiohttp.ClientConnectorError, aiohttp.ServerDisconnectedError)):
            schedule_retry(file_info)      # transient transport: retry later
        else:
            quarantine(file_info, repr(cause))  # likely file/options problem
    else:
        raise

Prevention

When it happens

Trigger: Calling the docling reader on a file when: the Docling server is unreachable after retries (ClientConnectorError), the server returns 4xx/5xx on POST /convert/source (bad options, auth failure, payload too large), the request exceeds timeouts, or the response JSON does not match DoclingApiOutputModel (pydantic ValidationError).

Common situations: Docling server not running or wrong api_base in settings; api_key/tenant headers rejected (401/403); Docling server version that rejects v1alpha options; very large base64 payloads rejected by a proxy (413); network flaps exceeding the 5-retry budget.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/76211f75c46e6e4d. Report an issue: GitHub.