{"record":{"id":"dec292e46b499e57","repo":"opendatalab/MinerU","slug":"middle-json-must-contain-a-list-field-named-pdf-in","errorCode":null,"errorMessage":"middle_json must contain a list field named pdf_info.","messagePattern":"middle_json must contain a list field named pdf_info\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mineru/cli/client_side_output.py","lineNumber":68,"sourceCode":"    middle_json_path = parse_dir / f\"{doc_stem}_middle.json\"\n    markdown_path = parse_dir / f\"{doc_stem}.md\"\n    content_list_path = parse_dir / f\"{doc_stem}_content_list.json\"\n    content_list_v2_path = parse_dir / f\"{doc_stem}_content_list_v2.json\"\n\n    if not middle_json_path.exists():\n        raise FileNotFoundError(f\"Missing middle json file: {middle_json_path}\")\n\n    middle_json = json.loads(middle_json_path.read_text(encoding=\"utf-8\"))\n    if not isinstance(middle_json, dict):\n        raise ValueError(\"middle_json must be a dict.\")\n    backend = middle_json.get(\"_backend\")\n    pdf_info = middle_json.get(\"pdf_info\")\n    if backend not in SUPPORTED_BACKENDS:\n        raise ValueError(\n            f\"Unsupported middle json backend for client-side output generation: {backend}\"\n        )\n    if not isinstance(pdf_info, list):\n        raise ValueError(\"middle_json must contain a list field named pdf_info.\")\n\n    if backend in PDF_BACKENDS:\n        finalize_client_side_middle_json(middle_json)\n        pdf_info = middle_json[\"pdf_info\"]\n\n    make_func = _select_union_make(backend)\n    image_dir = \"images\"\n\n    markdown_path.write_text(\n        make_func(pdf_info, MakeMode.MM_MD, image_dir),\n        encoding=\"utf-8\",\n    )\n    _write_json(\n        content_list_path,\n        make_func(pdf_info, MakeMode.CONTENT_LIST, image_dir),\n    )\n    _write_json(\n        content_list_v2_path,","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/opendatalab/MinerU/blob/4fe4bde114a23ee5dd637eae99b767f4669bf58c/mineru/cli/client_side_output.py#L50-L86","documentation":"ValueError from regenerate_client_side_outputs(): the pdf_info field of the middle json must be a list (one entry per page). Even when _backend is valid, a missing pdf_info (None), an object, or a scalar aborts client-side rendering before union_make is called.","triggerScenarios":"A middle json where 'pdf_info' was renamed, removed by a cleanup script, or replaced by a dict keyed by page number; also fires when the key exists but holds null.","commonSituations":"Downstream tools rewriting middle.json with a different schema; partial manual migration of old outputs; server versions that emit a differently-named field.","solutions":["Regenerate the middle json with a matching mineru version","If constructing the file manually, ensure pdf_info is a JSON array of page objects","Pre-validate the parsed structure (isinstance checks) before calling regenerate (see defense)","Avoid renaming/deleting keys when post-processing staged artifacts"],"exampleFix":"# before: {\"_backend\": \"vlm\", \"pdf_info\": {\"0\": {...}}}\n\n# after: {\"_backend\": \"vlm\", \"pdf_info\": [{...}]}","handlingStrategy":"type-guard","validationCode":"pdf_info = json.loads(middle_json_path.read_text(\"utf-8\")).get(\"pdf_info\")\nif not isinstance(pdf_info, list):\n    raise SystemExit(\"middle json schema mismatch: pdf_info must be a list; regenerate artifacts\")","typeGuard":"def has_pdf_info_list(payload: dict) -> bool:\n    return isinstance(payload.get(\"pdf_info\"), list)","tryCatchPattern":"try:\n    regenerate_client_side_outputs(parse_dir, doc_stem)\nexcept ValueError as e:\n    if \"pdf_info\" in str(e):\n        refetch_results()\n    else:\n        raise","preventionTips":["Do not rename or restructure keys in staged artifacts","Validate both _backend and pdf_info in one pre-check before rendering","Regenerate rather than hand-migrate old schemas"],"tags":["client-side","middle-json","schema","validation"],"backgroundTag":null,"analyzedSha":"4fe4bde114a23ee5dd637eae99b767f4669bf58c","analyzedAt":"2026-08-14T21:29:18.456Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}