{"record":{"id":"06c4b552e96d4612","repo":"Tencent/tinker","slug":"old-dex-signature-mismatch-expected-s-actual","errorCode":null,"errorMessage":"old dex signature mismatch! expected: %s, actual: %s","messagePattern":"old dex signature mismatch! expected: (.+?), actual: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"tinker-commons/src/main/java/com/tencent/tinker/commons/dexpatcher/DexPatchApplier.java","lineNumber":135,"sourceCode":"        // old dex we passed in.\n        if (this.patchFile == null) {\n            throw new IllegalArgumentException(\"patch file is null.\");\n        }\n        if (this.patchFile.getVersion() > DexPatchFile.VERSION_02) {\n            final int oldDexAPI = this.oldDex.getTableOfContents().api;\n            final int expectedOldDexAPI = this.patchFile.getOldDexAPI();\n            if (oldDexAPI != expectedOldDexAPI) {\n                throw new IOException(\"old dex version mismatch! expetced: \"\n                        + expectedOldDexAPI + \", actual: \" + oldDexAPI);\n            }\n        }\n        byte[] oldDexSign = this.oldDex.computeSignature(false);\n        if (oldDexSign == null) {\n            throw new IOException(\"failed to compute old dex's signature.\");\n        }\n        byte[] oldDexSignInPatchFile = this.patchFile.getOldDexSignature();\n        if (CompareUtils.uArrCompare(oldDexSign, oldDexSignInPatchFile) != 0) {\n            throw new IOException(\n                    String.format(\n                            \"old dex signature mismatch! expected: %s, actual: %s\",\n                            Arrays.toString(oldDexSign),\n                            Arrays.toString(oldDexSignInPatchFile)\n                    )\n            );\n        }\n\n        // Firstly, set sections' offset after patched, sort according to their offset so that\n        // the dex lib of aosp can calculate section size.\n        TableOfContents patchedToc = this.patchedDex.getTableOfContents();\n\n        patchedToc.api = patchFile.getPatchedDexAPI();\n        patchedToc.header.off = 0;\n        patchedToc.header.size = 1;\n        patchedToc.mapList.size = 1;\n\n        patchedToc.stringIds.off","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/tinker-commons/src/main/java/com/tencent/tinker/commons/dexpatcher/DexPatchApplier.java#L117-L153","documentation":"IOException from DexPatchApplier.executeAndSaveTo: the SHA-1 signature computed over the old dex does not match the old-dex signature stored in the patch file at generation time. This is the applier's core safety check — the patch was diffed against different bytes than the dex being patched.","triggerScenarios":"Applying a dex patch to any old dex whose content differs by even one byte from the dex used by tinker-patch when the patch was produced.","commonSituations":"Base apk re-built (even trivially) after patch generation; channels appending data to the dex; wrong base apk version in a multi-flavor setup; mixing debug and release artifacts.","solutions":["Regenerate the patch from the exact base apk currently installed/distributed","Verify channel/build variants match between diff time and apply time","Add an automated base-apk hash check in CI before releasing patches"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"byte[] actual = oldDex.computeSignature(false);\nif (actual == null || CompareUtils.uArrCompare(actual, patchFile.getOldDexSignature()) != 0) {\n    throw new IOException(\"base dex differs from patch target; regenerate patch\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    applier.executeAndSaveTo(out);\n} catch (IOException e) {\n    if (String.valueOf(e.getMessage()).startsWith(\"old dex signature mismatch\")) {\n        // halt rollout: installed base differs from patch base\n    } else { throw e; }\n}","preventionTips":["Record and check base apk hash in your patch delivery metadata","Never rebuild/re-sign the base apk between patch generation and distribution"],"tags":["dexpatcher","signature-mismatch","base-apk","patch-apply"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}