Tencent/tinker · error · TinkerRuntimeException

patch %s extract failed (%s).

Error message

patch %s extract failed (%s).

What it means

SoDiffPatchInternal's catch-all: any Throwable thrown while recovering native libraries from the patch (extracting old .so from the base APK, applying bsdiff or copying new/changed libraries, then MD5-verifying the result) is wrapped as 'patch lib extract failed'. Per-file MD5 verification failure is reported via onPatchTypeExtractFail and returns false; this exception indicates an unexpected Throwable escaped the so-recovery loop.

Source

Thrown at tinker-android/tinker-android-lib/src/main/java/com/tencent/tinker/lib/patch/SoDiffPatchInternal.java:210

                    } finally {
                        IOHelper.closeQuietly(oldStream);
                        IOHelper.closeQuietly(newStream);
                    }

                    //go go go bsdiff get the
                    if (!SharePatchFileUtil.verifyFileMd5(extractedFile, fileMd5)) {
                        ShareTinkerLog.w(TAG, "Failed to recover diff file " + extractedFile.getPath());
                        manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
                        SharePatchFileUtil.safeDeleteFile(extractedFile);
                        return false;
                    }
                    ShareTinkerLog.w(TAG, "success recover bsdiff file: %s, use time: %d",
                        extractedFile.getPath(), (System.currentTimeMillis() - start));
                }
            }

        } catch (Throwable e) {
            throw new TinkerRuntimeException("patch " + ShareTinkerInternals.getTypeString(type) + " extract failed (" + e.getMessage() + ").", e);
        } finally {
            SharePatchFileUtil.closeZip(apk);
            SharePatchFileUtil.closeZip(patch);
        }
        return true;
    }

}

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Generate the patch from the exact installed APK including the correct abi splits (use the same split/abi configuration when building the patch).
  2. Verify patch file MD5 before applying.
  3. Check free disk space and patch directory writability.
  4. If targeting new page-size devices, regenerate patches with an updated tinker/bsdiff toolchain that matches the .so layout.
  5. Inspect the wrapped cause via onPatchException.
Defensive patterns

Strategy: try-catch

Validate before calling

// Only distribute so patches for abis actually present in the installed APK
Set<String> supportedAbis = Build.SUPPORTED_ABIS_SET or splits config;
if (!serverPayload.patchAbis.containsAll(supportedAbisOfInstalledApk)) {
    stripSoFromFlagsOrRefuse();
}
if (!SharePatchFileUtil.verifyFileMd5(new File(patchPath), serverPayload.patchMd5)) {
    refuse("bad so patch");
}

Try / catch

try {
    TinkerInstaller.onReceiveUpgradePatch(context, patchPath);
} catch (TinkerRuntimeException e) {
    reportPatchApplyFailure(e.getCause() != null ? e.getCause() : e);
}

Prevention

When it happens

Trigger: Applying a so patch when: the old .so entry cannot be read from the base APK zip, the bsdiff stream for a library is malformed, output file creation under the patch lib directory fails (permissions/disk), or an abi-filtered APK lacks an expected library.

Common situations: Patch built for a different abi split or base APK than installed (split APKs with per-abi .so sets); devices with 16 KB page-size .so formats mismatching the patch's; disk full; patch generated with an incompatible tinker tool version.

Related errors


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