gradle/gradle · error · IllegalStateException
Unexpected lock protocol found in lock file. Expected %s, fo
Error message
Unexpected lock protocol found in lock file. Expected %s, found %s.
What it means
LockStateAccess parses the state region of a cache lock file, which is also version-prefixed; a mismatch between the on-disk protocol byte and the running Gradle's protocol raises this IllegalStateException. An empty or short region is not an error (EOFException yields the initial state), so it only fires when a complete record written by a different protocol version exists. Practically, another Gradle generation wrote this lock state.
Source
Thrown at platforms/core-execution/persistent-cache/src/main/java/org/gradle/cache/internal/filelock/LockStateAccess.java:84
try {
byte[] buffer = new byte[stateRegionSize];
lockFileAccess.seek(REGION_START);
int readPos = 0;
while (readPos < buffer.length) {
int nread = lockFileAccess.read(buffer, readPos, buffer.length - readPos);
if (nread < 0) {
break;
}
readPos += nread;
}
ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer, 0, readPos);
DataInputStream dataInput = new DataInputStream(inputStream);
byte protocolVersion = dataInput.readByte();
if (protocolVersion != protocol.getVersion()) {
throw new IllegalStateException(String.format("Unexpected lock protocol found in lock file. Expected %s, found %s.", protocol.getVersion(), protocolVersion));
}
return protocol.read(dataInput);
} catch (EOFException e) {
return protocol.createInitialState();
}
}
public FileLockOutcome tryLock(RandomAccessFile lockFileAccess, boolean shared) throws IOException {
try {
FileLock fileLock = lockFileAccess.getChannel().tryLock(REGION_START, stateRegionSize, shared);
if (fileLock == null) {
return FileLockOutcome.LOCKED_BY_ANOTHER_PROCESS;
} else {
return FileLockOutcome.acquired(fileLock);
}
} catch (OverlappingFileLockException e) {
return FileLockOutcome.LOCKED_BY_THIS_PROCESS;
}View on GitHub (pinned to 534f27719b)
Solutions
- Stop every running Gradle daemon across all installed versions, then retry
- Delete the lock files for the affected cache so fresh state is written
- Keep a single Gradle version per GRADLE_USER_HOME
- Standardize the Gradle wrapper version across teams and CI
Defensive patterns
Strategy: try-catch
Try / catch
try {
lockStateAccess.readState(lockFileAccess);
} catch (IllegalStateException e) {
if (String.valueOf(e.getMessage()).startsWith("Unexpected lock protocol")) {
// stale lock state from another Gradle version: delete the lock file
}
} Prevention
- Stop all daemons after a Gradle upgrade or downgrade
- Do not share GRADLE_USER_HOME between different Gradle versions
- Automate wrapper-version pinning in CI
When it happens
Trigger: Acquiring a cache lock whose state region was persisted by a Gradle build with a different lock state protocol, e.g. after a version switch with surviving daemons or shared caches.
Common situations: Switching Gradle versions while old daemons hold locks, mixed IDE/CLI versions on one machine, CI sharing a cache volume with developer workstations.
Related errors
- Unexpected lock protocol found in lock file. Expected %s, fo
- Could not open %s.
- Failed to initialize %s
- Unexpected protocol version %s received in lock contention n
- Invalidating {} as it was not closed cleanly.
AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22).
Data as JSON: /api/errors/bc15e911f402656d.
Report an issue: GitHub.