{"record":{"id":"890f26c5996bbd43","repo":"Tencent/tinker","slug":"stored-entry-size-compressed-size-mismatch","errorCode":null,"errorMessage":"STORED entry size/compressed size mismatch","messagePattern":"STORED entry size/compressed size mismatch","errorType":"exception","errorClass":"ZipException","httpStatus":null,"severity":"error","filePath":"third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipOutputStream.java","lineNumber":467,"sourceCode":"        int method = ze.getMethod();\n        if (method == -1) {\n            method = defaultCompressionMethod;\n        }\n        // If the method is STORED, check that the ZipEntry was configured appropriately.\n        if (method == STORED) {\n            if (ze.getCompressedSize() == -1) {\n                ze.setCompressedSize(ze.getSize());\n            } else if (ze.getSize() == -1) {\n                ze.setSize(ze.getCompressedSize());\n            }\n            if (ze.getCrc() == -1) {\n                throw new ZipException(\"STORED entry missing CRC\");\n            }\n            if (ze.getSize() == -1) {\n                throw new ZipException(\"STORED entry missing size\");\n            }\n            if (ze.size != ze.compressedSize) {\n                throw new ZipException(\"STORED entry size/compressed size mismatch\");\n            }\n        }\n        checkOpen();\n        // checkAndSetZip64Requirements(ze);\n\n        //zhangshaowen edit here, we just want the same time and modDate\n        ze.comment = null;\n        ze.extra = null;\n        ze.time = TIME_CONST;\n        ze.modDate = MOD_DATE_CONST;\n\n        nameBytes = ze.name.getBytes(StandardCharsets.UTF_8);\n        checkSizeIsWithinShort(\"Name\", nameBytes);\n        entryCommentBytes = BYTE;\n        if (ze.comment != null) {\n            entryCommentBytes = ze.comment.getBytes(StandardCharsets.UTF_8);\n            // The comment is not written out until the entry is finished, but it is validated here\n            // to fail-fast.","sourceCodeStart":449,"sourceCodeEnd":485,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipOutputStream.java#L449-L485","documentation":"For a STORED (uncompressed) entry the compressed size must equal the uncompressed size by definition. After the missing-size checks pass, putNextEntry() compares ze.size != ze.compressedSize and throws ZipException(\"STORED entry size/compressed size mismatch\") when the caller supplied two different values. This catches inconsistent metadata copied or computed by the caller before writing a corrupt local file header.","triggerScenarios":"putNextEntry(entry) with method STORED where setSize() and setCompressedSize() were both called with different values — typically size set from the original file but compressedSize copied from a DEFLATED source entry (or vice versa), or each populated from different variables in a copy loop.","commonSituations":"Copying entry metadata from a source zip that was DEFLATED into a STORED output: compressedSize (deflated length) differs from size (raw length); refactoring where one of the two setters is fed a different length variable; stale compressedSize left over after switching an entry's method to STORED.","solutions":["For STORED entries always set compressedSize = size explicitly: ze.setCompressedSize(ze.getSize()) (or set both to the same buffer length).","When copying from a source entry, recompute both fields from the raw data length rather than trusting source compressedSize.","Add an assert before putNextEntry: if method == STORED, assert size == compressedSize."],"exampleFix":"// before\ne.setSize(rawData.length);\ne.setCompressedSize(srcEntry.getCompressedSize()); // deflated length: mismatch\nzos.putNextEntry(e);\n\n// after\ne.setSize(rawData.length);\ne.setCompressedSize(rawData.length); // STORED: must equal size\nzos.putNextEntry(e);","handlingStrategy":"validation","validationCode":"static void assertStoredEntryConsistent(TinkerZipEntry e) {\n    if (e.getMethod() == TinkerZipEntry.STORED && e.getSize() != e.getCompressedSize()) {\n        throw new IllegalStateException(\"STORED size mismatch for \" + e.getName());\n    }\n}\n// call before putNextEntry(e)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["For STORED entries always setCompressedSize(getSize()) as the final metadata step","When copying from a DEFLATED source, recompute both sizes from raw data length"],"tags":["zip","java","tinker","stored-entry","size-mismatch"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}