{"record":{"id":"8a738b587ad7402b","repo":"apache/iceberg","slug":"failed-to-check-zookeeper-lock-status-8a738b","errorCode":null,"errorMessage":"Failed to check Zookeeper lock status","messagePattern":"Failed to check Zookeeper lock status","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/ZkLockFactory.java","lineNumber":232,"sourceCode":"        }\n\n        return acquired;\n      } catch (Exception e) {\n        LOG.warn(\"Failed to acquire Zookeeper lock\", e);\n        return false;\n      }\n    }\n\n    @Override\n    public boolean isHeld() {\n      return isHeld(sharedCount.getVersionedValue());\n    }\n\n    private static boolean isHeld(VersionedValue<Integer> versionedValue) {\n      try {\n        return versionedValue.getValue() == LOCKED;\n      } catch (Exception e) {\n        throw new RuntimeException(\"Failed to check Zookeeper lock status\", e);\n      }\n    }\n\n    @Override\n    public void unlock() {\n      try {\n        sharedCount.setCount(UNLOCKED);\n        LOG.debug(\"Released lock for path: {}\", lockPath);\n      } catch (Exception e) {\n        LOG.warn(\"Failed to release lock for path: {}\", lockPath, e);\n        throw new RuntimeException(\"Failed to release lock\", e);\n      }\n    }\n  }\n\n  @VisibleForTesting\n  RetryPolicy createRetryPolicy() {\n    ZKRetryPolicies effectivePolicy =","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/ZkLockFactory.java#L214-L250","documentation":"The lock wrapper's isHeld() compares the VersionedValue<Integer> fetched from the SharedCount to LOCKED. getValue() may throw (node missing, connection issues, deserialization) and any such Exception is rethrown as RuntimeException \"Failed to check Zookeeper lock status\", so lock-state inspection failed rather than returning false.","triggerScenarios":"tryLock() or isHeld() invoked when the SharedCount value cannot be read: ZooKeeper session expired, shared-count node deleted externally, or connection failure during get().","commonSituations":"ZooKeeper session loss during long maintenance cycles; another process deleted the lock znode; network blip while checking lock state before committing maintenance.","solutions":["Check the wrapped cause for KeeperException (SessionExpired/NoNode/ConnectionLoss)","Ensure ZooKeeper connectivity is stable; increase session timeout if sessions expire mid-cycle","Recreate the lock factory (open()) after a session loss — the SharedCount must be restarted","Prevent external tooling from deleting lock znodes under the base path"],"exampleFix":"// before\nif (!lockFactory.isHeld()) { ... } // RuntimeException on ZK failure\n// after\ntry {\n  if (!lockFactory.isHeld()) { ... }\n} catch (RuntimeException e) {\n  throw new IOException(\"ZK lock state unavailable, aborting maintenance\", e);\n}","handlingStrategy":"retry","validationCode":"// preflight health check\nclient.checkExists().forPath(lockPath); // ensure znode exists and session is fresh","typeGuard":null,"tryCatchPattern":"try { boolean held = factory.isHeld(); } catch (RuntimeException e) { /* reconnect / reopen factory before retrying */ }","preventionTips":["Increase session timeout to outlast long maintenance cycles","Reopen the lock factory after any KeeperException session loss","Block external deletion of lock znodes","Monitor ZK connection-loss metrics"],"tags":["zookeeper","locking","session-expired","flink"],"backgroundTag":"connection-refused","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}