{"record":{"id":"f2e292b906a86e4e","repo":"HKUDS/DeepTutor","slug":"mineru-archive-has-too-many-entries-len-members","errorCode":null,"errorMessage":"MinerU archive has too many entries ({len(members)}).","messagePattern":"MinerU archive has too many entries \\((.+?)\\)\\.","errorType":"exception","errorClass":"MinerUError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/parsing/engines/mineru/cloud.py","lineNumber":334,"sourceCode":"        import shutil\n\n        shutil.rmtree(path)\n    path.mkdir(parents=True, exist_ok=True)\n\n\ndef _extract_archive(archive_bytes: bytes, target_dir: Path) -> None:\n    \"\"\"Extract the MinerU zip into ``target_dir``, preserving its directory\n    tree (the ``images/`` subdir matters) while defending against Zip Slip and\n    zip bombs. Unlike :func:`safe_extract_zip`, this keeps subdirectories and\n    does not apply a document-extension whitelist — the archive is a trusted\n    MinerU artifact, not a user upload.\"\"\"\n    target_root = target_dir.resolve()\n    total = 0\n    try:\n        with zipfile.ZipFile(io.BytesIO(archive_bytes)) as archive:\n            members = [m for m in archive.infolist() if not m.is_dir()]\n            if len(members) > _MAX_ENTRIES:\n                raise MinerUError(f\"MinerU archive has too many entries ({len(members)}).\")\n            for member in members:\n                # Collapse to a POSIX-relative path and reject traversal.\n                rel = Path(member.filename.replace(\"\\\\\", \"/\"))\n                if rel.is_absolute() or \"..\" in rel.parts:\n                    logger.warning(\"Skipping unsafe zip member: %s\", member.filename)\n                    continue\n                dest = (target_root / rel).resolve()\n                if target_root not in dest.parents and dest != target_root:\n                    logger.warning(\"Skipping zip member escaping root: %s\", member.filename)\n                    continue\n                total += member.file_size\n                if total > _MAX_TOTAL_BYTES:\n                    raise MinerUError(\"MinerU archive exceeds the size limit.\")\n                dest.parent.mkdir(parents=True, exist_ok=True)\n                with archive.open(member) as src, open(dest, \"wb\") as out:\n                    out.write(src.read())\n    except zipfile.BadZipFile as exc:\n        raise MinerUError(f\"MinerU returned an invalid archive: {exc}\") from exc","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/parsing/engines/mineru/cloud.py#L316-L352","documentation":"The downloaded result zip contains more than _MAX_ENTRIES non-directory members, so extraction is refused as a zip-bomb guard.","triggerScenarios":"A result archive (legitimately huge doc or malicious/corrupt zip) whose member count exceeds _MAX_ENTRIES.","commonSituations":"Parsing a massive PDF producing thousands of artifact files; a corrupted download inflating the archive; pathological documents emitting per-glyph files.","solutions":["If legitimate: split the source PDF and parse in parts.","Re-download (retry) in case of corruption.","Raise _MAX_ENTRIES if you control the deployment and trust the source.","Check the PDF for corruption/oddities."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import io, zipfile\n\ndef archive_safe(data: bytes, max_entries: int) -> bool:\n    with zipfile.ZipFile(io.BytesIO(data)) as z:\n        return sum(1 for m in z.infolist() if not m.is_dir()) <= max_entries","typeGuard":null,"tryCatchPattern":"except MinerUError as e:\n    if \"too many entries\" in str(e):\n        split_pdf_and_reparse(pdf)","preventionTips":["Split very large PDFs before cloud parsing.","Retry once in case of a corrupted download.","Treat the cap as a zip-bomb guard — don't disable it blindly."],"tags":["mineru","cloud","zip","zip-bomb","security"],"backgroundTag":"zip-bomb-guard","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}