{"slug": "your-wheel-can-be-a-valid-zip-and-still-break-installers-i-built-a-checker-for", "title": "Your wheel can be a valid zip and still break installers. I built a checker for that.", "summary": "A developer built zipgate, an MIT-licensed Python tool that hand-parses ZIP local file headers and central directory entries to detect malformed ZIP64 extra fields (0x0001) that Python's zipfile silently tolerates but stricter installers reject. The tool was validated against two real incidents: a 5.8 GiB PyTorch ROCm nightly wheel that failed under uv with \"zip64 extended information field was too long\" (astral-sh/uv#19440), and wheel 0.47.0 silently writing illegal ZIP64 structures into retagged wheels (pypa/wheel#692), which zipgate flags as SPURIOUS_ZIP64_LOCAL while the 0.48.0 output passes. It ships with eight tests and byte-level fixtures for both incident classes, and exits 0 for valid, 1 for invalid, and 2 for unreadable wheels.", "body_md": "A 5.8 GiB PyTorch ROCm nightly wheel failed to install under uv with `zip64 extended information field was too long` ([astral-sh/uv#19440](https://github.com/astral-sh/uv/issues/19440)). Separately, `wheel tags` in wheel 0.47.0 was silently writing illegal ZIP64 structures into retagged wheels ([pypa/wheel#692](https://github.com/pypa/wheel/issues/692)).\n\nBoth are the same class of problem: the ZIP64 extra field (`0x0001`) in the file doesn't match what APPNOTE 4.5.3 requires. Python's `zipfile` reads these files fine — it silently tolerates the malformation — and then a stricter installer falls over.\n\nI parse local file headers and central directory entries by hand (not trusting `zipfile`) and validate:\n\n`0xFFFFFFFF`. This is exactly what wheel 0.47.0 did: an 8-byte ZIP64 extra in headers whose 32-bit sizes were perfectly fine.\nI reproduced the wheel#692 MRE (lowering `zipfile.ZIP64_LIMIT` to force the ZIP64 path on small files, as the issue suggests), built a wheel, and retagged it:\n\n| artifact | zipgate verdict | \n|---|---|\n| original wheel | VALID | \n| retagged with wheel 0.47.0 | **INVALID** —`SPURIOUS_ZIP64_LOCAL` on two entries | \n| retagged with wheel 0.48.0 | VALID | \n\nThe 0.47.0 output trips the exact rule the issue describes; 0.48.0 is clean.\n\n```\npip install zipgate\nzipgate dist/*.whl\n```\n\nExit `0` = all valid, `1` = at least one invalid, `2` = unreadable. Eight tests, byte-level fixtures for both incident classes.\n\nRepo: [hahahahahahahahah6/zipgate](https://github.com/hahahahahahahahah6/zipgate) (MIT).\n\nIf you ship wheels — especially big ones, or retagged ones — it's worth one command before upload.", "url": "https://wpnews.pro/news/your-wheel-can-be-a-valid-zip-and-still-break-installers-i-built-a-checker-for", "canonical_source": "https://dev.to/haoli/your-wheel-can-be-a-valid-zip-and-still-break-installers-i-built-a-checker-for-that-1baf", "published_at": "2026-10-04 07:21:35+00:00", "updated_at": "2026-10-04 07:42:28.612641+00:00", "lang": "en", "topics": ["developer-tools", "ai-infrastructure"], "entities": ["zipgate", "PyTorch", "ROCm", "uv", "wheel", "astral-sh/uv", "pypa/wheel", "Python"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/your-wheel-can-be-a-valid-zip-and-still-break-installers-i-built-a-checker-for", "markdown": "https://wpnews.pro/news/your-wheel-can-be-a-valid-zip-and-still-break-installers-i-built-a-checker-for.md", "text": "https://wpnews.pro/news/your-wheel-can-be-a-valid-zip-and-still-break-installers-i-built-a-checker-for.txt", "jsonld": "https://wpnews.pro/news/your-wheel-can-be-a-valid-zip-and-still-break-installers-i-built-a-checker-for.jsonld"}}