{"record":{"id":"d02035fc08020241","repo":"Tencent/tinker","slug":"rewritepatchinfofilewithlock-fail","errorCode":null,"errorMessage":"rewritePatchInfoFileWithLock fail","messagePattern":"rewritePatchInfoFileWithLock fail","errorType":"exception","errorClass":"TinkerRuntimeException","httpStatus":null,"severity":"critical","filePath":"tinker-android/tinker-android-loader-no-op/src/main/java/com/tencent/tinker/loader/shareutil/SharePatchInfo.java","lineNumber":106,"sourceCode":"\n        return patchInfo;\n    }\n\n    public static boolean rewritePatchInfoFileWithLock(File pathInfoFile, SharePatchInfo info, File lockFile) {\n        if (pathInfoFile == null || info == null || lockFile == null) {\n            return false;\n        }\n        File lockParentFile = lockFile.getParentFile();\n        if (!lockParentFile.exists()) {\n            lockParentFile.mkdirs();\n        }\n        boolean rewriteSuccess;\n        ShareFileLockHelper fileLock = null;\n        try {\n            fileLock = ShareFileLockHelper.getFileLock(lockFile);\n            rewriteSuccess = rewritePatchInfoFile(pathInfoFile, info);\n        } catch (Exception e) {\n            throw new TinkerRuntimeException(\"rewritePatchInfoFileWithLock fail\", e);\n        } finally {\n            try {\n                if (fileLock != null) {\n                    fileLock.close();\n                }\n            } catch (IOException e) {\n                ShareTinkerLog.i(TAG, \"releaseInfoLock error\", e);\n            }\n\n        }\n        return rewriteSuccess;\n    }\n\n    private static SharePatchInfo readAndCheckProperty(File pathInfoFile) {\n        boolean isReadPatchSuccessful = false;\n        int numAttempts = 0;\n        String oldVer = null;\n        String newVer = null;","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/tinker-android/tinker-android-loader-no-op/src/main/java/com/tencent/tinker/loader/shareutil/SharePatchInfo.java#L88-L124","documentation":"SharePatchInfo.rewritePatchInfoFileWithLock takes the lock file and rewrites the info file (rewritePatchInfoFile). Any exception during locking or the atomic rewrite is wrapped in TinkerRuntimeException('rewritePatchInfoFileWithLock fail'). Unlike the read path, this happens while persisting patch metadata — typically during patch apply/upgrade — so the patch state on disk may be out of sync.","triggerScenarios":"Disk full or storage read-only when writing infoFile; lock file parent directory creation failing; serialization of the info throwing; the destination file being deleted concurrently by another process mid-write.","commonSituations":"Low-storage devices during patch apply; multiple processes (or a watchdog) cleaning the tinker directory while another applies a patch; file system errors after OTA.","solutions":["Check and free device storage before applying patches; treat this failure as 'patch not applied' and retry the full apply flow.","Ensure only the designated process applies patches and nothing else deletes the tinker directory concurrently.","Call Tinker.cleanPatch() to return to a consistent base state, then re-download and re-apply.","Inspect the exception cause (caused-by) — IOException points to storage, other causes to lock contention."],"exampleFix":"// before\nboolean ok = SharePatchInfo.rewritePatchInfoFileWithLock(infoFile, info, lockFile);\n\n// after\nboolean ok;\ntry {\n    ok = SharePatchInfo.rewritePatchInfoFileWithLock(infoFile, info, lockFile);\n} catch (TinkerRuntimeException e) {\n    ShareTinkerLog.e(TAG, \"rewrite info fail, patch state may be stale\", e);\n    ok = false;\n}","handlingStrategy":"try-catch","validationCode":"if (Environment.getExternalStorageState(...) is bad || dir.getFreeSpace() < MIN_BYTES) { /* defer patch apply */ }","typeGuard":null,"tryCatchPattern":"catch TinkerRuntimeException 'rewritePatchInfoFileWithLock fail' -> mark patch apply as failed, cleanPatch(), retry on next launch","preventionTips":["Check free disk space before applying patches.","Apply patches in a single dedicated process.","Never delete or write the tinker directory from outside tinker's own flow."],"tags":["patch-info","file-lock","io","storage"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}