Tencent/tinker · error · TinkerRuntimeException

error patch package check fail , but file is null

Error message

error patch package check fail , but file is null

What it means

Tinker throws this TinkerRuntimeException while dispatching the patch-load result code ERROR_LOAD_PATCH_PACKAGE_CHECK_FAIL in TinkerLoadResult. That result code means the patch package failed its security/integrity check during loading, and the normal path is to report onLoadPackageCheckFail(patchVersionFile, errorCode) to the app's LoadReporter. The exception fires only when the patchVersionFile is null at that point, which is an internal invariant violation: the load pipeline produced a 'package check failed' result but no longer knows which versioned patch file to blame.

Source

Thrown at tinker-android/tinker-android-lib/src/main/java/com/tencent/tinker/lib/tinker/TinkerLoadResult.java:188

            case ShareConstants.ERROR_LOAD_PATCH_VERSION_DIRECTORY_NOT_EXIST:
                ShareTinkerLog.e(TAG, "patch version directory not found, current version:%s", currentVersion);
                tinker.getLoadReporter().onLoadFileNotFound(patchVersionDirectory,
                    ShareConstants.TYPE_PATCH_FILE, true);
                break;

            case ShareConstants.ERROR_LOAD_PATCH_VERSION_FILE_NOT_EXIST:
                ShareTinkerLog.e(TAG, "patch version file not found, current version:%s", currentVersion);
                if (patchVersionFile == null) {
                    throw new TinkerRuntimeException("error load patch version file not exist, but file is null");
                }
                tinker.getLoadReporter().onLoadFileNotFound(patchVersionFile,
                    ShareConstants.TYPE_PATCH_FILE, false);
                break;
            case ShareConstants.ERROR_LOAD_PATCH_PACKAGE_CHECK_FAIL:
                ShareTinkerLog.i(TAG, "patch package check fail");
                if (patchVersionFile == null) {
                    throw new TinkerRuntimeException("error patch package check fail , but file is null");
                }
                int errorCode = intentResult.getIntExtra(ShareIntentUtil.INTENT_PATCH_PACKAGE_PATCH_CHECK, ShareConstants.ERROR_LOAD_GET_INTENT_FAIL);
                tinker.getLoadReporter().onLoadPackageCheckFail(patchVersionFile, errorCode);
                break;
            case ShareConstants.ERROR_LOAD_PATCH_VERSION_DEX_DIRECTORY_NOT_EXIST:
                if (dexDirectory != null) {
                    ShareTinkerLog.e(TAG, "patch dex file directory not found:%s", dexDirectory.getAbsolutePath());
                    tinker.getLoadReporter().onLoadFileNotFound(dexDirectory,
                        ShareConstants.TYPE_DEX, true);
                } else {
                    //should be not here
                    ShareTinkerLog.e(TAG, "patch dex file directory not found, warning why the path is null!!!!");
                    throw new TinkerRuntimeException("patch dex file directory not found, warning why the path is null!!!!");
                }
                break;
            case ShareConstants.ERROR_LOAD_PATCH_VERSION_DEX_FILE_NOT_EXIST:
                String dexPath = ShareIntentUtil.getStringExtra(intentResult,
                    ShareIntentUtil.INTENT_PATCH_MISSING_DEX_PATH);

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Ensure cleanPatch()/onPatchRollback() is never invoked while a load is in flight; serialize patch lifecycle operations through one process (usually the :patch process or main process only).
  2. Verify the patch info file and /tinker/<version>/ directory still exist before triggering a load attempt; re-install or clean the patch from a LoadReporter callback such as onLoadFileNotFound.
  3. Upgrade to the latest Tinker version, where several null-invariant races in TinkerLoadResult were hardened.
  4. If reproducible, capture the tinker log (ShareTinkerLog) around the crash and check whether the version directory was removed mid-load.
Defensive patterns

Strategy: try-catch

Validate before calling

File infoFile = new File(context.getFilesDir().getParent() + "/tinker/patch_info");
File versionDir = new File(new File(infoFile.getParent(), "patch-" + currentVersion), "");
if (!infoFile.exists() || !versionDir.isDirectory()) {
    Tinker.with(context).cleanPatch(); // do not attempt load on inconsistent state
}

Try / catch

try {
    Tinker.with(context).loadPatch();
} catch (TinkerRuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("file is null")) {
        Tinker.with(context).cleanPatch(); // state inconsistent, reset
    } else { throw e; }
}

Prevention

When it happens

Trigger: A patch install attempt returns result code ERROR_LOAD_PATCH_PACKAGE_CHECK_FAIL from the loader intent, and simultaneously patchVersionFile (looked up from patch info / version directory) resolves to null. Typically caused by the patch version directory or info file being deleted (e.g. by cleanPatch, another process, or a cleanup service) between the load attempt and result handling.

Common situations: Calling TinkerInstaller.cleanPatch() or Tinker.with(ctx).cleanPatch() concurrently with a patch load; two processes racing to load/clean the same patch; a corrupted or half-written /tinker/patch info state after a killed process; disk-cleanup tools removing tinker directories.

Related errors


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