{"record":{"id":"93a6fe5024d04c2d","repo":"opendatalab/MinerU","slug":"invalid-xlsx-package-file-is-not-a-zip-archive","errorCode":null,"errorMessage":"Invalid XLSX package: file is not a ZIP archive.","messagePattern":"Invalid XLSX package: file is not a ZIP archive\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mineru/model/xlsx/package_normalizer.py","lineNumber":52,"sourceCode":"MAX_EXCEL_COLUMN = \"XFD\"\n\n\ndef normalize_xlsx_package(file_bytes: bytes) -> bytes:\n    \"\"\"在进入 openpyxl 前修复常见 XLSX 包级兼容问题。\"\"\"\n    try:\n        with ZipFile(BytesIO(file_bytes)) as source:\n            rewritten_members: list[tuple[ZipInfo, bytes]] = []\n            changed = False\n\n            for info in source.infolist():\n                member_data = source.read(info.filename)\n                normalized_data = _normalize_xlsx_member(info.filename, member_data)\n                if normalized_data != member_data:\n                    changed = True\n                member_data = normalized_data\n                rewritten_members.append((info, member_data))\n    except BadZipFile as exc:\n        raise ValueError(\"Invalid XLSX package: file is not a ZIP archive.\") from exc\n\n    if not changed:\n        return file_bytes\n\n    return _write_package(rewritten_members)\n\n\ndef _normalize_xlsx_member(member_name: str, member_data: bytes) -> bytes:\n    \"\"\"根据 XLSX 包内成员路径分发 XML 兼容性规范化逻辑。\"\"\"\n    if member_name == SHARED_STRINGS_PATH:\n        return _normalize_shared_strings_xml(member_data)\n    if member_name == STYLES_PATH:\n        return _normalize_styles_xml(member_data)\n    if _is_worksheet_xml(member_name):\n        return _normalize_worksheet_xml(member_data)\n    return member_data\n\n","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/opendatalab/MinerU/blob/4fe4bde114a23ee5dd637eae99b767f4669bf58c/mineru/model/xlsx/package_normalizer.py#L34-L70","documentation":"Raised by MineRU's XLSX package normalizer when the input bytes passed off as an .xlsx workbook are not a ZIP archive at all. Every real XLSX file is a ZIP container (OOXML), so Python's zipfile.ZipFile raises BadZipFile when opening it, which the normalizer re-raises as this ValueError. Typical root causes: a renamed .xls (legacy binary BIFF), .csv, or HTML file with an .xlsx extension, a truncated upload, or plain-text/HTML error content returned by a download instead of the spreadsheet.","triggerScenarios":"Calling the XLSX parsing entry point (mineru.model.xlsx package_normalizer) with bytes that fail ZipFile(BytesIO(file_bytes)) — e.g. feeding a legacy .xls (OLE2 compound document starting with D0 CF 11 E0), a CSV, or an HTML page saved as .xlsx. Only files whose leading bytes are not a ZIP local-file-header signature (PK\\x03\\x04, including empty/self-extracting variants) trigger it.","commonSituations":"Users export 'Excel' from a web tool that actually emits CSV/HTML; a legacy .xls is renamed to .xlsx; a partially downloaded or zero-byte file is processed; a proxy returns an HTML login page with a 200 status that gets saved with the original filename.","solutions":["Verify the file is genuinely XLSX: check the first 4 bytes are b'PK\\x03\\x04' (file magic) or run `file report.xlsx` — it should say 'Microsoft Excel 2007+'.","If the file is a legacy .xls, CSV, or HTML table, re-export it as 'Excel Workbook (.xlsx)' from the source application before feeding it to MineRU.","If the file came over HTTP, re-download it and confirm the response is not an HTML error page (check Content-Type and body); enable HTTP status checking so failures surface at download time.","If the file may be corrupt, try opening it in Excel/LibreOffice — if they also fail, obtain a fresh copy."],"exampleFix":"// before\nwith open(path, 'rb') as f:\n    result = parse_xlsx(f.read())  # ValueError: Invalid XLSX package\n\n// after\ndef load_xlsx(path):\n    data = Path(path).read_bytes()\n    if not data.startswith(b'PK'):\n        raise ValueError(f'{path} is not an XLSX (ZIP) archive; re-export as .xlsx')\n    return parse_xlsx(data)","handlingStrategy":"validation","validationCode":"def is_valid_xlsx(data: bytes) -> bool:\n    return len(data) >= 4 and data[:4] == b'PK\\x03\\x04'","typeGuard":"def is_xlsx_zip(data: bytes) -> bool:\n    return isinstance(data, (bytes, bytearray)) and bytes(data[:4]) == b'PK\\x03\\x04'","tryCatchPattern":"try:\n    result = parse_xlsx(data)\nexcept ValueError as e:\n    if 'not a ZIP archive' in str(e):\n        raise HTTPException(415, 'File is not a valid XLSX workbook; re-export as .xlsx') from e\n    raise","preventionTips":["Check the PK\\x03\\x04 magic bytes of every uploaded .xlsx before handing it to the parser.","Never trust file extensions from user uploads; validate content signatures at the trust boundary.","When downloading files over HTTP, fail on non-2xx and verify Content-Type before saving with the original filename."],"tags":["xlsx","file-format","zip","validation","mineru"],"backgroundTag":null,"analyzedSha":"4fe4bde114a23ee5dd637eae99b767f4669bf58c","analyzedAt":"2026-08-14T21:29:18.456Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}