Tencent/tinker · error · IOException

Tinker Exception:FileLockHelper lock file failed: {}

Error message

Tinker Exception:FileLockHelper lock file failed: {}

What it means

ShareFileLockHelper acquires an exclusive java.nio FileLock on a lock file, retrying with sleeps; if localFileLock is still null after all attempts it throws IOException("Tinker Exception:FileLockHelper lock file failed: <path>") with the last saveException as cause. FileLock.tryLock can fail on filesystems that do not support POSIX locks or when another process/thread holds the lock.

Source

Thrown at tinker-android/tinker-android-loader/src/main/java/com/tencent/tinker/loader/shareutil/ShareFileLockHelper.java:66

                if (isGetLockSuccess) {
                    break;
                }

            } catch (Exception e) {
                saveException = e;
                ShareTinkerLog.e(TAG, "getInfoLock Thread failed time:" + LOCK_WAIT_EACH_TIME);
            }

            //it can just sleep 0, afraid of cpu scheduling
            try {
                Thread.sleep(LOCK_WAIT_EACH_TIME);
            } catch (Exception ignore) {
                ShareTinkerLog.e(TAG, "getInfoLock Thread sleep exception", ignore);
            }
        }

        if (localFileLock == null) {
            throw new IOException("Tinker Exception:FileLockHelper lock file failed: " + lockFile.getAbsolutePath(), saveException);
        }
        fileLock = localFileLock;
    }

    public static ShareFileLockHelper getFileLock(File lockFile) throws IOException {
        return new ShareFileLockHelper(lockFile);
    }

    @Override
    public void close() throws IOException {
        try {
            if (fileLock != null) {
                fileLock.release();
            }
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Ensure only one process performs patch operations (guard with a process-level lock or route patching to the main process).
  2. Make sure the lock file's parent directory exists and is writable before acquiring.
  3. If a stale lock persists after a crash, reboot or clear the app's tinker directory so the lock file is recreated.
  4. Catch IOException around getFileLock callers (readAndCheckPropertyWithLock / rewritePatchInfoFileWithLock) and surface a retryable patch failure instead of crashing.
  5. Upgrade Tinker — newer versions tune lock wait/retry behavior.

Example fix

// before
fileLock = ShareFileLockHelper.getFileLock(lockFile);
// after
try {
    fileLock = ShareFileLockHelper.getFileLock(lockFile);
} catch (IOException e) {
    ShareTinkerLog.w(TAG, "lock busy, retry patch later", e);
    return false;
}
Defensive patterns

Strategy: retry

Validate before calling

File lockParent = lockFile.getParentFile();
if (lockParent == null || (!lockParent.exists() && !lockParent.mkdirs())) {
    // cannot lock: fix directory before calling getFileLock
}
if (!lockParent.canWrite()) {
    // read-only storage: patch ops will fail
}

Try / catch

try {
    ShareFileLockHelper lock = ShareFileLockHelper.getFileLock(lockFile);
    try { /* critical section */ } finally { lock.close(); }
} catch (IOException e) {
    // lock acquisition failed after retries: back off and retry the whole op later
}

Prevention

When it happens

Trigger: ShareFileLockHelper.getFileLock(lockFile) when tryLock() repeatedly throws IOException (e.g. lock held elsewhere, or the FS does not support locking) until the retry budget is exhausted.

Common situations: Patch info read/rewrite while a previous Tinker operation crashed holding the lock on some devices; multi-process apps where two processes patch simultaneously; certain OEM filesystems/emulated storage where FileLock is unsupported; lock file on a read-only or corrupted directory.

Related errors


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