{"record":{"id":"f054d1d656d7ef8b","repo":"Tencent/tinker","slug":"file-name-filename-file-size-filesize-entry","errorCode":null,"errorMessage":"file name:${filename}, file size${fileSize}, entry name:${entryName}, entry localHeaderRelOffset:${localHeaderRelOffset}, ${msg} signature not found; was ${hexString}","messagePattern":"file name:(.+?), file size(.+?), entry name:(.+?), entry localHeaderRelOffset:(.+?), (.+?) signature not found; was (.+?)","errorType":"exception","errorClass":"ZipException","httpStatus":null,"severity":"error","filePath":"third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipFile.java","lineNumber":233,"sourceCode":"            // If we don't have a zip64 eocd record, we read values from the \"regular\"\n            // eocd record.\n            int diskNumber = it.readShort() & 0xffff;\n            int diskWithCentralDir = it.readShort() & 0xffff;\n            numEntries = it.readShort() & 0xffff;\n            int totalNumEntries = it.readShort() & 0xffff;\n            it.skip(4); // Ignore centralDirSize.\n            centralDirOffset = ((long) it.readInt()) & 0xffffffffL;\n            if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {\n                throw new ZipException(\"Spanned archives not supported\");\n            }\n        }\n        final int commentLength = it.readShort() & 0xffff;\n        return new EocdRecord(numEntries, centralDirOffset, commentLength);\n    }\n\n    static void throwZipException(String filename, long fileSize, String entryName, long localHeaderRelOffset, String msg, int magic) throws ZipException {\n        final String hexString = Integer.toHexString(magic);\n        throw new ZipException(\"file name:\" + filename\n                               + \", file size\" + fileSize\n                               + \", entry name:\" + entryName\n                               + \", entry localHeaderRelOffset:\" + localHeaderRelOffset\n                               + \", \"\n                               + msg + \" signature not found; was \" + hexString);\n    }\n\n    /**\n     * Closes this zip file. This method is idempotent. This method may cause I/O if the\n     * zip file needs to be deleted.\n     *\n     * @throws IOException\n     *             if an IOException occurs.\n     */\n    public void close() throws IOException {\n        // guard.close();\n        RandomAccessFile localRaf = raf;\n        if (localRaf != null) { // Only close initialized instances","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipFile.java#L215-L251","documentation":"throwZipException is the generic guard for magic-number mismatches: when the library seeks to an entry's local file header and the first 4 bytes are not the 'PK\\x03\\x04' signature, it throws a ZipException that embeds the file name, file size, entry name, the entry's localHeaderRelOffset, the kind of header that failed, and the actual (wrong) signature in hex. The context fields let you tell whether the offset itself is wrong or the bytes at the offset are garbage.","triggerScenarios":"TinkerZipFile.getInputStream(entry) on an entry whose local header offset points at non-header bytes — e.g. the archive was rewritten/concatenated after the central directory was parsed, the zip has a prepended payload (self-extracting exe) with stale offsets, or the file is truncated/corrupted.","commonSituations":"APK/patch files modified after the central directory was indexed (e.g. binary-diff tools rewriting in place); self-extracting archives where central-dir offsets need adjustment; partial downloads where the tail is intact but the body is not; zips with data descriptors confusing offset math.","solutions":["Inspect the reported localHeaderRelOffset and hex signature: a plausible offset with garbage bytes means the file body changed after indexing — reopen the TinkerZipFile so the central directory is re-read from the current file.","If the archive was modified (patched, repackaged, SFX-wrapped), rebuild it cleanly so central-directory offsets match the file contents.","Re-download or restore the file from a known-good source; verify with an independent tool (unzip -t) before retrying."],"exampleFix":"// before\nTinkerZipFile zf = new TinkerZipFile(file); // opened before file was patched\nInputStream is = zf.getInputStream(entry); // stale offsets\n\n// after\nzf.close();\nfile = rebuildOrRedownload(file);\ntry (TinkerZipFile zf2 = new TinkerZipFile(file)) {\n    InputStream is = zf2.getInputStream(zf2.getEntry(entry.getName()));\n}","handlingStrategy":"try-catch","validationCode":"// hard to pre-validate cheaply; instead never mutate a file while it is open\n// reopen after any external modification:\nif (file.lastModified() > openTimestamp) {\n    zf.close();\n    zf = new TinkerZipFile(file);\n}","typeGuard":null,"tryCatchPattern":"try {\n    InputStream is = zf.getInputStream(entry);\n} catch (ZipException e) {\n    if (e.getMessage().contains(\"signature not found\")) {\n        // archive changed under us or is corrupt: reopen once from a verified copy, else fail\n        log.error(\"Local header mismatch for {} at {}: {}\", entry.getName(), file, e.getMessage());\n        throw new IOException(\"Archive inconsistent, refusing to read: \" + file, e);\n    }\n    throw e;\n}","preventionTips":["Treat zip files as immutable while a TinkerZipFile is open; reopen after external rewrites.","Checksum archives before processing so corruption is detected before offsets are used.","Never modify an APK/zip in place (patch, resign, SFX-wrap) while readers hold it open."],"tags":["zip","corruption","offset","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}