zylon-ai/private-gpt · error · ValueError

No content could be extracted from document source (type={do

Error message

No content could be extracted from document source (type={doc_block.source.type!r}).

What it means

ValueError from _process_document (chat history preprocessor). It converts a DocumentBlock's source to text via source.to_text(convert_service) on a worker thread; if the result is empty or None, no LITextBlock can be built and it raises, naming the source type. This guards the ingestion path where every document attachment must yield text for the chat history.

Source

Thrown at private_gpt/components/chat/processors/chat_history/documents/document_preprocessor.py:62

    doc_index: int
    reference: str | None = None
    content: str | list[ResultContentBlockType] | None = None
    error_detail: str | None = None


class DocumentProcessingResponse(BaseModel):
    message: ChatMessage | None = None
    processing_status: DocumentProcessingStatus | None = None
    chat_history: list[ChatMessage] | None = None


async def _process_document(
    doc_block: DocumentBlock,
    convert_service: DocumentConverter,
) -> LITextBlock:
    text = await asyncio.to_thread(doc_block.source.to_text, convert_service)
    if not text:
        raise ValueError(
            f"No content could be extracted from document source "
            f"(type={doc_block.source.type!r})."
        )

    parts: list[str] = []
    if doc_block.title:
        parts.append(f"Title: {doc_block.title}")
    if doc_block.context:
        parts.append(f"Context: {doc_block.context}")
    parts.append(text)

    return LITextBlock(text="\n\n".join(parts))


async def preprocess_document_message(
    message: ChatMessage,
    convert_service: DocumentConverter,
    max_concurrency: int | None = None,

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Open the uploaded file locally and confirm it actually contains extractable text (pdftotext, cat).
  2. For scanned PDFs/images, enable an OCR-capable converter or OCR the file before upload.
  3. Reject empty/unsupported files at the API boundary before they reach the chat pipeline (check size and content type).
  4. Check the reported source type in the message to see which converter branch returned nothing.

Example fix

// before
# upload scanned.pdf (no text layer) -> chat request
ValueError: No content could be extracted from document source (type='file').

// after
# OCR first, then upload
$ ocrmypdf in.pdf out.pdf && curl -F file=@out.pdf ...
Defensive patterns

Strategy: validation

Validate before calling

text = await asyncio.to_thread(doc_block.source.to_text, convert_service)
if not text or not text.strip():
    raise HTTPException(422, f"Document yielded no text (source type={doc_block.source.type!r})")

Type guard

def document_has_extractable_text(path: str) -> bool:
    import subprocess
    return subprocess.run(["pdftotext", path, "-"], capture_output=True).stdout.strip() != b""

Try / catch

try:
    block = await _process_document(doc_block, converter)
except ValueError as e:
    raise HTTPException(422, str(e)) from e

Prevention

When it happens

Trigger: Uploading an image/PDF/binary whose conversion yields nothing (empty PDF, scanned image without OCR, corrupt file), a 0-byte file, or a source type whose to_text returns '' for this converter configuration.

Common situations: Scanned PDFs with no OCR backend configured; empty or password-protected documents; unsupported formats that the DocumentConverter silently skips; upload endpoints accepting files without content checks.

Related errors


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