docling-project/docling · error · RuntimeError
PagePreprocessingModel returned unexpected number of pages
Error message
PagePreprocessingModel returned unexpected number of pages
What it means
The preprocessing stage of StandardPdfPipeline runs PagePreprocessingModel over a batch of valid pages and asserts that the number of processed pages returned equals the number of pages submitted. A length mismatch means the preprocessing model changed the page count, breaking the ThreadedItem bookkeeping that maps results back to (run_id, page_no, conv_res). As with error 341, this is an internal invariant guard that fires when a custom or modified preprocessing model violates its contract.
Source
Thrown at docling/pipeline/standard_pdf_pipeline.py:529
try:
if _log.isEnabledFor(logging.DEBUG):
_t_start = time.time()
_t_mono = time.monotonic()
pages = [page for _, page in valid]
processed_pages = list(
self.model(valid[0][0].conv_res, pages) # type: ignore[arg-type]
)
if _log.isEnabledFor(logging.DEBUG):
_log.debug(
"PIPELINE_PROFILING Stage preprocess: run_id=%d pages=%s start=%.3f end=%.3f duration=%.3fs",
rid,
[it.page_no for it, _ in valid],
_t_start,
time.time(),
time.monotonic() - _t_mono,
)
if len(processed_pages) != len(pages):
raise RuntimeError(
"PagePreprocessingModel returned unexpected number of pages"
)
for idx, processed_page in enumerate(processed_pages):
result.append(
ThreadedItem(
payload=processed_page,
run_id=rid,
page_no=valid[idx][0].page_no,
conv_res=valid[idx][0].conv_res,
)
)
except Exception as exc:
_log.error(
"Stage preprocess failed for run %d, pages %s: %s",
rid,
[it.page_no for it, _ in valid],
exc,
exc_info=False,View on GitHub (pinned to 61d76f1ff3)
Solutions
- Return one processed page per input page from the custom preprocessing model; mark unprocessed pages with an empty/failed payload rather than omitting them.
- If page filtering is genuinely needed, do it before handing pages to the pipeline (filter conv_res.pages) rather than inside the model.
- Align docling and docling-core versions (pip install -U docling docling-core) so the model contract matches.
- Reproduce with stock pipeline options to confirm the customization is the cause.
Example fix
# before
class MyPreprocessModel(PagePreprocessingModel):
def __call__(self, conv_res, pages):
return [p for p in pages if not is_blank(p)] # drops pages -> mismatch
# after
class MyPreprocessModel(PagePreprocessingModel):
def __call__(self, conv_res, pages):
return [empty_processed_page(p) if is_blank(p) else p for p in pages] Defensive patterns
Strategy: try-catch
Try / catch
try:
result = converter.convert(doc)
except RuntimeError as e:
if 'unexpected number of pages' in str(e):
# preprocessing model changed page count; return 1:1 results instead
... Prevention
- Filter pages before the pipeline, never inside a preprocessing model.
- Custom preprocessing models must preserve the input page count.
- Run with stock pipeline options first to isolate customization bugs.
When it happens
Trigger: Overriding or replacing the preprocessing model so it filters, merges, or drops pages; a custom pipeline that injects its own PagePreprocessingModel subclass returning fewer results than input pages; version skew between docling-core model code and pipeline code.
Common situations: Adding a custom preprocessing step (e.g. blank-page removal) that skips pages instead of returning an empty processed page; running with locally patched docling-core where the model return shape changed; mixing docling and docling-core versions from different releases.
Related errors
- Model {self.name} returned wrong number of pages
- No pipeline could be initialized for format {format}
- No pipeline could be initialized for {in_doc.file}.
- Extraction failed for: {ext_res.input.file} with status: {ex
- No extraction pipeline could be initialized for {in_doc.file
AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14).
Data as JSON: /api/errors/8933a6840d9a6fc3.
Report an issue: GitHub.