{"record":{"id":"6419263e0160eefa","repo":"Tencent/tinker","slug":"error-load-patch-version-file-not-exist-but-file-641926","errorCode":null,"errorMessage":"error load patch version file not exist, but file is null","messagePattern":"error load patch version file not exist, but file is null","errorType":"exception","errorClass":"TinkerRuntimeException","httpStatus":null,"severity":"critical","filePath":"tinker-android/tinker-android-lib/src/main/java/com/tencent/tinker/lib/tinker/TinkerLoadResult.java","lineNumber":180,"sourceCode":"            case ShareConstants.ERROR_LOAD_PATCH_INFO_CORRUPTED:\n                ShareTinkerLog.e(TAG, \"path info corrupted\");\n                tinker.getLoadReporter().onLoadPatchInfoCorrupted(oldVersion, newVersion, patchInfoFile);\n                break;\n\n            case ShareConstants.ERROR_LOAD_PATCH_INFO_BLANK:\n                ShareTinkerLog.e(TAG, \"path info blank, wait main process to restart\");\n                break;\n\n            case ShareConstants.ERROR_LOAD_PATCH_VERSION_DIRECTORY_NOT_EXIST:\n                ShareTinkerLog.e(TAG, \"patch version directory not found, current version:%s\", currentVersion);\n                tinker.getLoadReporter().onLoadFileNotFound(patchVersionDirectory,\n                    ShareConstants.TYPE_PATCH_FILE, true);\n                break;\n\n            case ShareConstants.ERROR_LOAD_PATCH_VERSION_FILE_NOT_EXIST:\n                ShareTinkerLog.e(TAG, \"patch version file not found, current version:%s\", currentVersion);\n                if (patchVersionFile == null) {\n                    throw new TinkerRuntimeException(\"error load patch version file not exist, but file is null\");\n                }\n                tinker.getLoadReporter().onLoadFileNotFound(patchVersionFile,\n                    ShareConstants.TYPE_PATCH_FILE, false);\n                break;\n            case ShareConstants.ERROR_LOAD_PATCH_PACKAGE_CHECK_FAIL:\n                ShareTinkerLog.i(TAG, \"patch package check fail\");\n                if (patchVersionFile == null) {\n                    throw new TinkerRuntimeException(\"error patch package check fail , but file is null\");\n                }\n                int errorCode = intentResult.getIntExtra(ShareIntentUtil.INTENT_PATCH_PACKAGE_PATCH_CHECK, ShareConstants.ERROR_LOAD_GET_INTENT_FAIL);\n                tinker.getLoadReporter().onLoadPackageCheckFail(patchVersionFile, errorCode);\n                break;\n            case ShareConstants.ERROR_LOAD_PATCH_VERSION_DEX_DIRECTORY_NOT_EXIST:\n                if (dexDirectory != null) {\n                    ShareTinkerLog.e(TAG, \"patch dex file directory not found:%s\", dexDirectory.getAbsolutePath());\n                    tinker.getLoadReporter().onLoadFileNotFound(dexDirectory,\n                        ShareConstants.TYPE_DEX, true);\n                } else {","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/tinker-android/tinker-android-lib/src/main/java/com/tencent/tinker/lib/tinker/TinkerLoadResult.java#L162-L198","documentation":"Thrown by TinkerLoadResult#load in the ERROR_LOAD_PATCH_VERSION_FILE_NOT_EXIST branch when patchVersionFile is null. The load code already says the version file (patch-xxx.apk info file) is missing; the code then needs that File to report onLoadFileNotFound. A null file means the result Intent lacked the version-file path extra, so the state is internally inconsistent.","triggerScenarios":"The load-result Intent carries ERROR_LOAD_PATCH_VERSION_FILE_NOT_EXIST but no patch-version-file path, so patchVersionFile was never populated when TinkerLoadResult parsed the Intent — e.g. after the patch directory was partially deleted externally while the load result Intent from a previous run persisted.","commonSituations":"Users or cleanup tools deleting /data/data/<pkg>/tinker contents between the load attempt and result reporting; multi-process races where :patch process rewrites state while the main process reads stale Intent extras; version mismatch between gradle plugin and library producing Intents without the expected extras.","solutions":["Call Tinker.with(app).cleanPatch() to wipe inconsistent patch state, then relaunch without the patch.","Verify the patch directory is only manipulated by tinker (no external 'clear cache' jobs touching /tinker).","Keep tinker gradle plugin and tinker-android-lib versions in lockstep so Intent extras always match."],"exampleFix":"// guard in a startup try/catch\ntry {\n    TinkerInstaller.onReceiveUpgradePatch(context, patchPath);\n} catch (TinkerRuntimeException e) {\n    Tinker.with(context).cleanPatch(); // reset inconsistent patch state\n}","handlingStrategy":"fallback","validationCode":"// verify patch state consistency before/around applying\nFile patchDir = Tinker.with(app).getPatchDirectory();\nif (patchDir != null && patchDir.exists()) {\n    File info = new File(patchDir, \"patch.info\"); // state must not be half-deleted\n    if (!info.exists()) {\n        Tinker.with(app).cleanPatch();\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    TinkerInstaller.onReceiveUpgradePatch(context, patchPath);\n} catch (TinkerRuntimeException e) {\n    Tinker.with(context).cleanPatch(); // reset inconsistent patch state, app runs unpatched\n}","preventionTips":["Exclude the tinker directory from any cache-cleaning or storage-manager jobs.","Manipulate patch files only through Tinker APIs, never with direct file deletes.","Pin gradle plugin and library versions together so Intent extras always match."],"tags":["tinker","android","patch-file","state-corruption","load-result"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}