Tencent/tinker · critical · IOException
failed to compute old dex's signature.
Error message
failed to compute old dex's signature.
What it means
IOException from DexPatchApplier.executeAndSaveTo: Dex.computeSignature returned null, so the applier cannot verify the old dex matches the patch's expected signature. computeSignature fails when the dex is too short or its map section cannot be read — i.e., the old dex input is not a usable dex.
Source
Thrown at tinker-commons/src/main/java/com/tencent/tinker/commons/dexpatcher/DexPatchApplier.java:131
}
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)
)
);
}
// Firstly, set sections' offset after patched, sort according to their offset so that
// the dex lib of aosp can calculate section size.
TableOfContents patchedToc = this.patchedDex.getTableOfContents();
patchedToc.api = patchFile.getPatchedDexAPI();
patchedToc.header.off = 0;View on GitHub (pinned to 1b7ea02c23)
Solutions
- Log and inspect the old dex bytes (length, header magic 'dex\n035') before applying
- Fix the extraction path so the full original dex (not odex/vdex artifacts) is fed in
- Re-download or restore the base dex/apk if corrupted
Example fix
// before
byte[] oldDexBuf = loadMaybeCorruptedDex();
new DexPatchApplier(new Dex(oldDexBuf), patchFile).executeAndSaveTo(out);
// after
byte[] oldDexBuf = loadMaybeCorruptedDex();
if (oldDexBuf == null || oldDexBuf.length < 112 || !oldDexBuf[0]=='d') throw new IOException("bad old dex");
new DexPatchApplier(new Dex(oldDexBuf), patchFile).executeAndSaveTo(out); Defensive patterns
Strategy: validation
Validate before calling
byte[] buf = readAll(oldDexStream);
if (buf.length < 112
|| buf[0] != 'd' || buf[1] != 'e' || buf[2] != 'x' || buf[3] != '\n') {
throw new IOException("old dex unreadable (len=" + buf.length + ")");
}
new DexPatchApplier(new Dex(buf), patchFile).executeAndSaveTo(out); Prevention
- Validate dex header magic, file length, and checksum before patch application
- Extract the original dex (not odex/vdex) with a tested code path
When it happens
Trigger: Passing a truncated, empty, or non-dex buffer as oldDex to DexPatchApplier; the dex was corrupted before patch application began.
Common situations: Reading the old dex from a bad odex/vdex extraction path, a partially written file, or a decompressed stream that failed; on-device patch applying where the base dex could not be fully loaded.
Related errors
- old dex version mismatch! expetced:
- old dex signature mismatch! expected: %s, actual: %s
- bad patch operation sequence. addCounter: %d, addCount: %d,
- ShareSecurityCheck file %s, size %d verifyPatchMetaSignature
- get public key md5 is null
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/6343541dd0c6f4ea.
Report an issue: GitHub.