{"record":{"id":"6f2b362a57c2e564","repo":"Tencent/tinker","slug":"too-many-entries-for-the-zip-file-format-s-16-bit","errorCode":null,"errorMessage":"Too many entries for the zip file format's 16-bit entry count","messagePattern":"Too many entries for the zip file format's 16-bit entry count","errorType":"exception","errorClass":"ZipException","httpStatus":null,"severity":"error","filePath":"third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/AlignedZipOutputStream.java","lineNumber":331,"sourceCode":"            }\r\n            if (ze.getCrc() == -1) {\r\n                throw new ZipException(\"STORED entry missing CRC\");\r\n            }\r\n            if (ze.getSize() == -1) {\r\n                throw new ZipException(\"STORED entry missing size\");\r\n            }\r\n            if (ze.getSize() != ze.getCompressedSize()) {\r\n                throw new ZipException(\"STORED entry size/compressed size mismatch\");\r\n            }\r\n        }\r\n\r\n        checkOpen();\r\n\r\n        if (entries.contains(ze.getName())) {\r\n            throw new ZipException(\"Entry already exists: \" + ze.getName());\r\n        }\r\n        if (entries.size() == 64*1024-1) {\r\n            throw new ZipException(\"Too many entries for the zip file format's 16-bit entry count\");\r\n        }\r\n        nameBytes = ze.getName().getBytes(Charset.forName(\"UTF-8\"));\r\n        nameLength = nameBytes.length;\r\n        if (nameLength > 0xffff) {\r\n            throw new IllegalArgumentException(\"Name too long: \" + nameLength + \" UTF-8 bytes\");\r\n        }\r\n\r\n        def.setLevel(compressionLevel);\r\n        ze.setMethod(method);\r\n\r\n        currentEntry = ze;\r\n        entries.add(currentEntry.getName());\r\n\r\n        // Local file header.\r\n        // http://www.pkware.com/documents/casestudies/APPNOTE.TXT\r\n        int flags = (method == STORED) ? 0 : GPBF_DATA_DESCRIPTOR_FLAG;\r\n        // Java always outputs UTF-8 filenames. (Before Java 7, the RI didn't set this flag and used\r\n        // modified UTF-8. From Java 7, it sets this flag and uses normal UTF-8.)\r","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/AlignedZipOutputStream.java#L313-L349","documentation":"The zip format's central directory records the entry count in a 16-bit field, capping a classic zip at 65,535 entries. This stream does not implement Zip64, so once the running entries set reaches 64*1024-1 the next putNextEntry is refused. The check happens before any bytes are written for the new entry, keeping the archive consistent.","triggerScenarios":"Writing an archive with more than 65,535 entries — e.g. packaging a project with tens of thousands of resource/asset files, or accidentally adding generated/duplicated files in a loop until the limit is hit.","commonSituations":"Large apps whose res/ + assets/ + generated code push past 64K files; a build step that accidentally emits per-class or per-locale files without dedupe; using this non-Zip64 writer where the input archive is already near the limit (Android's AAPT-era limit is a known relative of this one).","solutions":["Count entries before writing: if the planned set exceeds 65,535, prune redundant files (unused resources, duplicate metadata) until under the limit.","Split the output into multiple archives (e.g. assets split, expansion files, multidex-style sharding) so each stays under 65,535 entries.","If a single huge archive is a hard requirement, use a Zip64-capable writer for that artifact instead of this class, then verify consumers can read Zip64."],"exampleFix":"// before: unconditional add in a loop\nfor (File f : files) {\n    zos.putNextEntry(new ZipEntry(prefix + f.getName())); // throws at 65535th\n}\n\n// after: pre-validate the entry budget\nif (files.size() > 64 * 1024 - 1) {\n    throw new IllegalStateException(\"too many zip entries; split the archive\");\n}\nfor (File f : files) {\n    zos.putNextEntry(new ZipEntry(prefix + f.getName()));\n}","handlingStrategy":"validation","validationCode":"// Check the entry budget up front\nstatic final int MAX_ZIP_ENTRIES = 64 * 1024 - 1;\nif (plannedEntryNames.size() > MAX_ZIP_ENTRIES) {\n    throw new IllegalStateException(\"archive would exceed the 65535-entry zip limit; split or prune\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    zos.putNextEntry(entry);\n} catch (java.util.zip.ZipException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"16-bit entry count\")) {\n        // finish the current archive, roll over to a new part\n        zos.close();\n        zos = openNewPart();\n        zos.putNextEntry(entry);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Count planned entries before starting the archive.","Prune duplicate/generated files early in the packaging pipeline.","If huge single archives are expected, choose a Zip64-capable writer from the start."],"tags":["zip","entry-limit","zip64","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}