apache/iceberg · error · RuntimeException
Failed to check Zookeeper lock status
Error message
Failed to check Zookeeper lock status
What it means
ZkLockFactory's lock compares a versioned SharedCount value against LOCKED to decide whether the lock is held. If reading the value from ZooKeeper throws any Exception (connection loss, session expired, node missing), it is wrapped in RuntimeException("Failed to check Zookeeper lock status"). This prevents treating an unreadable lock state as "unlocked".
Source
Thrown at flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/ZkLockFactory.java:232
}
return acquired;
} catch (Exception e) {
LOG.warn("Failed to acquire Zookeeper lock", e);
return false;
}
}
@Override
public boolean isHeld() {
return isHeld(sharedCount.getVersionedValue());
}
private static boolean isHeld(VersionedValue<Integer> versionedValue) {
try {
return versionedValue.getValue() == LOCKED;
} catch (Exception e) {
throw new RuntimeException("Failed to check Zookeeper lock status", e);
}
}
@Override
public void unlock() {
try {
sharedCount.setCount(UNLOCKED);
LOG.debug("Released lock for path: {}", lockPath);
} catch (Exception e) {
LOG.warn("Failed to release lock for path: {}", lockPath, e);
throw new RuntimeException("Failed to release lock", e);
}
}
}
@VisibleForTesting
RetryPolicy createRetryPolicy() {
ZKRetryPolicies effectivePolicy =View on GitHub (pinned to 86d9c8fc54)
Solutions
- Check the wrapped cause for KeeperException types (CONNECTIONLOSS, SESSIONEXPIRED, NONODE) and address that specific problem.
- Ensure open() (or factory.create()) was invoked before tryLock; isHeld on an unstarted SharedCount fails.
- Verify the znode path for the lockId still exists; recreate it by re-opening the factory if it was deleted.
- Stabilize the ZK session (tune session timeout, avoid long GC pauses) and retry the operation with backoff.
- Run only one instance per lockId to avoid external interference with the counter znode.
Example fix
// before Lock lock = factory.createLock(); // open() never called boolean locked = lock.tryLock(); // -> Failed to check Zookeeper lock status // after LockFactory lf = factory.create(); // opens client + SharedCounts Lock lock = lf.createLock(); boolean locked = lock.tryLock();
Defensive patterns
Strategy: retry
Validate before calling
if (!lockFactory.isInitialized() /* ensure open() ran */) throw new IllegalStateException("Call create()/open() before tryLock"); Try / catch
try { boolean locked = lock.tryLock(); } catch (RuntimeException e) { if ("Failed to check Zookeeper lock status".equals(e.getMessage())) { /* check ZK session, retry with backoff */ } else throw e; } Prevention
- Always initialize via factory create()/open() before any lock operations.
- Tune ZK session timeout and avoid long GC pauses that expire sessions.
- Monitor KeeperException causes: CONNECTIONLOSS vs SESSIONEXPIRED vs NONODE need different fixes.
- Protect trigger znodes from external deletion and run a single instance per lockId.
When it happens
Trigger: tryLock or isHeld reads the SharedCount's VersionedValue and the underlying ZK get fails: connection loss, session expiry, the counter znode has not been created/started, or the znode was deleted externally.
Common situations: ZooKeeper session expired after a GC pause or network partition; someone/something deleted the trigger's znode path; open() was never called so the SharedCounts are not running; flaky network between Flink and the ensemble.
Related errors
- Connection to Zookeeper timed out
- Failed to initialize SharedCount
- Failed to check Zookeeper lock status
- Failed to initialize SharedCount
- Interrupted while connecting to Zookeeper
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/2e3011946a22eaf0.
Report an issue: GitHub.