Tencent/tinker · error · TinkerRuntimeException
patch %s extract failed (%s).
Error message
patch %s extract failed (%s).
What it means
Thrown by DexDiffPatchInternal when any Throwable escapes the dex recovery loop (extracting, repacking, bsdiff/dex-patch applying, and class-N dex merging) during patch application. The exception message embeds the patch type ('dex') and the original throwable's message. It is a catch-all wrapper: the real failure is the wrapped cause.
Source
Thrown at tinker-android/tinker-android-lib/src/main/java/com/tencent/tinker/lib/patch/DexDiffPatchInternal.java:626
patchDexFile(apk, patch, rawApkFileEntry, patchFileEntry, info, extractedFile);
if (!SharePatchFileUtil.verifyDexFileMd5(extractedFile, extractedFileMd5)) {
ShareTinkerLog.w(TAG, "Failed to recover dex file when verify patched dex: " + extractedFile.getPath());
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.rawName, type);
SharePatchFileUtil.safeDeleteFile(extractedFile);
return false;
}
ShareTinkerLog.w(TAG, "success recover dex file: %s, size: %d, use time: %d",
extractedFile.getPath(), extractedFile.length(), (System.currentTimeMillis() - start));
}
}
if (!mergeClassNDexFiles(context, patchFile, dir)) {
return false;
}
} catch (Throwable e) {
throw new TinkerRuntimeException("patch " + ShareTinkerInternals.getTypeString(type) + " extract failed (" + e.getMessage() + ").", e);
} finally {
SharePatchFileUtil.closeZip(apk);
SharePatchFileUtil.closeZip(patch);
}
return true;
}
/**
* repack dex to jar
*
* @param zipFile
* @param entryFile
* @param extractTo
* @param targetMd5
* @return boolean
* @throws IOException
*/
private static boolean extractDexToJar(ZipFile zipFile, ZipEntry entryFile, File extractTo, String targetMd5) throws IOException {View on GitHub (pinned to 1b7ea02c23)
Solutions
- Ensure the tinkerId of the installed base APK exactly matches the one used to build the patch (check ShareTinkerInternals/getManifestMeta or your build config).
- Verify the patch file MD5 before applying to rule out a truncated or tampered download.
- Match tinker gradle plugin and lib versions between patch build and app runtime.
- Inspect the wrapped cause in the TinkerRuntimeException (and your PatchReporter.onPatchException callback) to identify whether it is dex format, zip, or memory related.
- For large multi-dex apps, apply patches while the app is idle and memory pressure is low; consider tinker's dex split config.
Example fix
// before
TinkerInstaller.onReceiveUpgradePatch(context, patchFile);
// after
try {
TinkerInstaller.onReceiveUpgradePatch(context, patchFile);
} catch (TinkerRuntimeException e) {
Throwable cause = e.getCause() != null ? e.getCause() : e;
reportToServer(cause); // keep the wrapped cause, not just the message
} Defensive patterns
Strategy: try-catch
Validate before calling
// Verify base APK tinkerId matches the patch's before applying
String currentId = ShareTinkerInternals.getTinkerId(context);
if (currentId == null || !currentId.equals(serverPayload.baseTinkerId)) {
refusePatch("tinkerId mismatch");
}
if (!SharePatchFileUtil.verifyFileMd5(new File(patchPath), serverPayload.patchMd5)) {
refusePatch("patch md5 mismatch");
} Try / catch
try {
TinkerInstaller.onReceiveUpgradePatch(context, patchPath);
} catch (Throwable t) {
Throwable cause = (t instanceof TinkerRuntimeException && t.getCause() != null) ? t.getCause() : t;
patchReporter.onPatchException(cause);
} Prevention
- Pin tinkerId per release and verify it server-side before distributing a patch.
- Keep tinker gradle plugin and tinker-android-lib versions in lockstep.
- Report the wrapped cause (getCause), not the wrapper message, when triaging dex failures.
When it happens
Trigger: Applying a dex diff patch when: the old dex stream in the base APK is corrupted or not the expected format for DexPatchApplier, the patch stream is malformed, a ZipException occurs reading dex-in-jar entries, an OutOfMemoryError occurs on huge dex files, or mergeClassNDexFiles throws while combining classesN.dex files.
Common situations: Patch built against a different base APK than the one installed (tinkerId mismatch); patch generated by an incompatible tinker version; multidex APKs where classes2.dex/N layout changed between build and apply; proguard/r8 mapping drift changing dex contents; low-memory devices applying large multi-dex patches.
Related errors
- patch dex file directory not found, warning why the path is
- patch dex file not found, but path is null!!!!
- can't recognize dex mode:{}
- Expected ${DEX_IN_JAR_NAME} in ${file}
- patch ${type} extract failed (${message}).
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/460d0b24b6f1b635.
Report an issue: GitHub.