Tencent/tinker · error · IOException
Tinker Exception:FileLockHelper lock file failed: {}
Error message
Tinker Exception:FileLockHelper lock file failed: {} What it means
ShareFileLockHelper's constructor tries to acquire an exclusive FileLock on the lock file, retrying with Thread.sleep(LOCK_WAIT_EACH_TIME) up to a bounded number of attempts; the saveException from each try is kept. When all attempts fail it throws IOException('Tinker Exception:FileLockHelper lock file failed: <path>', saveException), exposing the last underlying failure (often OverlappingFileLockException, ClosedChannelException, or EMFILE too many open files).
Source
Thrown at tinker-android/tinker-android-loader-no-op/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
- Centralize patch apply/load operations in one process (e.g. only the main process or a dedicated :patch process) to remove lock contention.
- Close every ShareFileLockHelper via try-with-resources/finally; leaked helpers hold locks and exhaust FDs.
- Inspect the suppressed saveException cause: OverlappingFileLockException means same-JVM contention; Too many open files means an FD leak elsewhere in the app.
- If a stale lock survives a crashed process, cleanPatch() or app restart releases it (FileLock releases on process death).
Example fix
// before (leaks lock, later callers fail)
ShareFileLockHelper fileLock = ShareFileLockHelper.getFileLock(lockFile);
writeInfo(info);
// lock never closed
// after
try (ShareFileLockHelper fileLock = ShareFileLockHelper.getFileLock(lockFile)) {
writeInfo(info);
} Defensive patterns
Strategy: fallback
Validate before calling
public static void withLock(File lockFile, Callable<Void> body) throws IOException {
try (ShareFileLockHelper lock = ShareFileLockHelper.getFileLock(lockFile)) {
body.call();
} // always released
} Try / catch
try (ShareFileLockHelper lock = ShareFileLockHelper.getFileLock(f)) {
doWork();
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("lock file failed")) {
// contention or FD exhaustion: back off and retry later
}
} Prevention
- Close every ShareFileLockHelper in finally / try-with-resources
- Restrict patch operations to a single process
- Watch for FD leaks (Too many open files as the saveException cause)
When it happens
Trigger: getFileLock(lockFile) called while another thread/process already holds the lock for longer than the total retry window; the lock file was deleted while held; the process ran out of file descriptors so the channel could not be opened; channel closed concurrently.
Common situations: Multiple processes (main + :patch + push) applying or loading patches simultaneously; a previous crash leaving the lock held; heavy FD usage leaking channels; tinker info file locking contended during patch apply on slow devices.
Related errors
- Tinker Exception:FileLockHelper lock file failed: {}
- readAndCheckPropertyWithLock fail
- rewritePatchInfoFileWithLock fail
- patch ${type} extract failed (${message}).
- patch %s extract failed (%s).
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/acad970982df8026.
Report an issue: GitHub.