Tencent/tinker · critical · IOException
old dex version mismatch! expetced:
Error message
old dex version mismatch! expetced:
What it means
IOException from DexPatchApplier.executeAndSaveTo: for patch format v03+, the patch file records the dex API level of the old dex it was generated against, and the runtime old dex's TableOfContents.api differs. The patch cannot be applied because section layout differs between the two dex versions.
Source
Thrown at tinker-commons/src/main/java/com/tencent/tinker/commons/dexpatcher/DexPatchApplier.java:125
DexPatchFile patchFileIn
) {
this.oldDex = oldDexIn;
this.patchFile = patchFileIn;
this.patchedDex = new Dex(patchFileIn.getPatchedDexSize());
this.oldToPatchedIndexMap = new SparseIndexMap();
}
public void executeAndSaveTo(OutputStream out) throws IOException {
// Before executing, we should check if this patch can be applied to
// old dex we passed in.
if (this.patchFile == null) {
throw new IllegalArgumentException("patch file is null.");
}
if (this.patchFile.getVersion() > DexPatchFile.VERSION_02) {
final int oldDexAPI = this.oldDex.getTableOfContents().api;
final int expectedOldDexAPI = this.patchFile.getOldDexAPI();
if (oldDexAPI != expectedOldDexAPI) {
throw new IOException("old dex version mismatch! expetced: "
+ expectedOldDexAPI + ", actual: " + oldDexAPI);
}
}
byte[] oldDexSign = this.oldDex.computeSignature(false);
if (oldDexSign == null) {
throw new IOException("failed to compute old dex's signature.");
}
byte[] oldDexSignInPatchFile = this.patchFile.getOldDexSignature();
if (CompareUtils.uArrCompare(oldDexSign, oldDexSignInPatchFile) != 0) {
throw new IOException(
String.format(
"old dex signature mismatch! expected: %s, actual: %s",
Arrays.toString(oldDexSign),
Arrays.toString(oldDexSignInPatchFile)
)
);
}
View on GitHub (pinned to 1b7ea02c23)
Solutions
- Regenerate the patch against the exact base apk currently distributed
- Keep build toolchain versions identical between the patch-generation build and the released base package
- Enforce base-version checks in your patch distribution service before delivery
Defensive patterns
Strategy: validation
Validate before calling
if (patchFile.getVersion() > DexPatchFile.VERSION_02
&& oldDex.getTableOfContents().api != patchFile.getOldDexAPI()) {
throw new IOException("refusing to apply: dex api mismatch, regenerate patch for this base");
} Try / catch
try {
applier.executeAndSaveTo(out);
} catch (IOException e) {
if (String.valueOf(e.getMessage()).startsWith("old dex version mismatch")) {
// signal server to rebuild patch against installed base version
} else { throw e; }
} Prevention
- Freeze AGP/compileSdk between base release and patch builds
- Distribute patches keyed by base apk version and verify server-side
When it happens
Trigger: Applying a v03+ dex patch to an old dex whose api field (dex version, e.g., 035 vs 038) differs from getOldDexAPI() recorded at diff time.
Common situations: Base apk rebuilt with a different AGP/compileSdk (changing dex version) after the patch was made; applying a patch to the wrong base version; distributing patches built against a debug build to a release build.
Related errors
- failed to compute old dex's signature.
- old dex signature mismatch! expected: %s, actual: %s
- bad patch operation sequence. addCounter: %d, addCount: %d,
- bad dex patch file version:
- Unexpected type:
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/ea659d7aa5329253.
Report an issue: GitHub.