Tencent/tinker · error · TinkerRuntimeException

patch ${type} extract failed (${message}).

Error message

patch ${type} extract failed (${message}).

What it means

Thrown by ArkHotDiffPatchInternal when an IOException escapes while extracting ArkHot (ArkAPK hotfix) patch entries from the patch ZIP into the patch version directory. The raw IOException is wrapped in a TinkerRuntimeException whose message is prefixed with the patch type string ('ark hot' or similar). It signals an I/O-level failure in patch package extraction, not a checksum or format mismatch (those are reported via onPatchTypeExtractFail).

Source

Thrown at tinker-android/tinker-android-lib/src/main/java/com/tencent/tinker/lib/patch/ArkHotDiffPatchInternal.java:87

                File extractedFile = new File(dir + info.name);
                if (extractedFile.exists()) {
                    if (md5.equals(SharePatchFileUtil.getMD5(extractedFile))) {
                        continue;
                    } else {
                        extractedFile.delete();
                    }
                } else {
                    extractedFile.getParentFile().mkdirs();
                }

                ZipEntry patchFileEntry = patch.getEntry(patchRealPath);
                if (!extract(patch, patchFileEntry, extractedFile, md5, false)) {
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
                    return false;
                }
            }
        } catch (IOException e) {
            throw new TinkerRuntimeException("patch " + ShareTinkerInternals.getTypeString(type)
                    + " extract failed (" + e.getMessage() + ").", e);
        } finally {
            SharePatchFileUtil.closeZip(patch);
        }

        return true;
    }

    private static boolean patchArkHotLibraryExtract(Context context, String patchVersionDirectory,
                                                     String meta, File patchFile) {
        String dir = patchVersionDirectory + "/" + ShareConstants.ARKHOTFIX_PATH + "/";

        arkPatchList.clear();
        ShareArkHotDiffPatchInfo.parseDiffPatchInfo(meta, arkPatchList);

        if (!extractArkHotLibrary(context, dir, patchFile, TYPE_ARKHOT_SO)) {
            return false;
        }

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Verify the downloaded patch file's MD5 against the value distributed by the server before calling TinkerInstaller.onReceiveUpgradePatch.
  2. Check available disk space and that the patch directory (context.getFilesDir()/tinker) is writable before applying.
  3. Re-download the patch and retry the apply; a truncated ZIP is the most frequent cause.
  4. Confirm the patch was built with the same base APK (same tinkerId) and with ArkHot patching enabled in the gradle plugin.
  5. If it persists, capture the wrapped IOException cause and report it via your PatchReporter implementation.

Example fix

// before
TinkerInstaller.onReceiveUpgradePatch(context, patchFile);

// after
String expectedMd5 = serverPayload.patchMd5;
if (!SharePatchFileUtil.verifyFileMd5(patchFile, expectedMd5)) {
    // discard and re-download instead of applying a broken patch
    SharePatchFileUtil.safeDeleteFile(patchFile);
    return;
}
TinkerInstaller.onReceiveUpgradePatch(context, patchFile);
Defensive patterns

Strategy: try-catch

Validate before calling

String md5 = serverPayload.patchMd5;
if (!SharePatchFileUtil.verifyFileMd5(new File(patchPath), md5)) {
    SharePatchFileUtil.safeDeleteFile(new File(patchPath));
    requestPatchReDownload();
    return;
}
if (context.getCacheDir().getFreeSpace() < MIN_PATCH_SPACE) {
    notifyUserStorageLow();
    return;
}

Try / catch

try {
    TinkerInstaller.onReceiveUpgradePatch(context, patchPath);
} catch (TinkerRuntimeException e) {
    // e.getCause() is the original IOException
    reportPatchApplyFailure(e.getCause());
}

Prevention

When it happens

Trigger: Calling the ArkHot patch apply path (patchArkHotLibraryExtract / extractValidFile with the ark hot patch type) when: the patch ZIP entry for the ark so/dex cannot be read (patch.getEntry returns a broken stream), the destination file under patchVersionDirectory/arkhot/ cannot be created (parent dirs unwritable, disk full), or the ZIP stream is closed mid-read.

Common situations: Patch file truncated by an interrupted download; device storage exhausted or /data/data quota hit; patch directory permission changed after a backup/restore; patch package generated with a mismatched ArkHot layout (built against a different base APK or non-Ark build).

Related errors


AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14). Data as JSON: /api/errors/90dbe621780fbf7f. Report an issue: GitHub.