Skip to content

remote::docling-serve can send an empty file when using async mode #6393

Description

@pgustafs

System Info

OS: Red Hat Enterprise Linux 10.1, x86_64
Podman: 5.6.0
Python: 3.12.13
OGX: 1.3.1.dev0

The affected code is also present in OGX 1.3.0.

docling-slim: 2.119.0
docling-serve: v1.26.0 CPU container
Provider: remote::docling-serve
Provider mode: async (the default)

No GPU is required to reproduce the problem.

Information

  • The official example scripts
  • My own modified scripts

🐛 Describe the bug

When remote::docling-serve uses async mode, OGX writes the uploaded
document to a NamedTemporaryFile and immediately gives the temporary
file path to AsyncDoclingServiceClient.

The temporary file is not flushed first. The Docling client opens the
same path using another file handle, so it can read an empty file.

This happens in both async methods:

- `_convert_no_chunk_async()`
- `_convert_and_chunk_async()`

It affects conversion with and without chunking. It is easiest to
reproduce with a small file because the full write remains in Python's
buffer.

The temporary file also has no original extension. Docling Serve
therefore receives a temporary filename and
application/octet-stream instead of the original filename and MIME
type.

This code van have been introduced as part of
#6014.

Steps to reproduce

Configure the Docling Serve provider in async mode:

file_processors:
  - provider_id: docling-serve
    provider_type: remote::docling-serve
    config:
      base_url: http://localhost:5001
      mode: async

Start OGX and Docling Serve.

Create a small HTML document:

printf '<html><body><p>Hello from a small document.</p></body></html>' \
  > /tmp/small.html

Send it to the file processor with chunking enabled:

curl -sS \
  -F 'file=@/tmp/small.html;type=text/html' \
  -F 'chunking_strategy={"type":"auto"}' \
  http://localhost:8321/v1alpha/file-processors/process

The response contains no chunks.

The same problem can be reproduced by uploading a small document
through /v1/files and then adding it to a vector store. In that flow,
file ingestion fails with:

No chunks were generated from the file

The buffering problem can also be demonstrated without Docling:

import tempfile
from pathlib import Path

content = b"x" * 2414

with tempfile.NamedTemporaryFile() as tmp:
    tmp.write(content)

    print(len(Path(tmp.name).read_bytes()))
    # Prints 0

    tmp.flush()

    print(len(Path(tmp.name).read_bytes()))
    # Prints 2414

Suggested fix

Instead of creating a temporary file, pass a Docling DocumentStream
containing the original filename and bytes:

from io import BytesIO
from docling_core.types.io import DocumentStream

source = DocumentStream(
    name=filename,
    stream=BytesIO(content),
)

Use this source in both client.submit() and
client.submit_chunk().

This preserves:

  • The complete document content
  • The original filename
  • The file extension
  • The correct MIME type

A smaller fix would call tmp.flush() and create the temporary file
with the correct suffix. However, DocumentStream avoids the temporary
file and preserves the full original filename.

Tests should cover both async conversion paths and assert that the
client receives the original filename and all input bytes. An
integration test should use a small document so the buffering problem
is reliably detected.

Error logs

Docling Serve receives an empty file:

File 0: name=tmppbuw_vps, size=0 bytes,
md5=d41d8cd98f00, content_type=application/octet-stream

Input document tmppbuw_vps with format None does not match any allowed format.

Document tmppbuw_vps failed to convert.

Processed 1 docs generating 0 chunks.

When the document is added to a vector store, OGX reports:

File ingestion ended with status 'failed':

{
  "code": "server_error",
  "message": "No chunks were generated from the file"
}

There is no OGX Python traceback because the Docling async request itself succeeds. It returns a result containing no chunks.

Expected behavior

Docling Serve should receive the complete uploaded document with its
original filename and correct MIME type.

Async conversion should produce the same document or chunks as sync
conversion. Adding the file to a vector store should complete
successfully.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions