{"record":{"id":"44102c735baf1e55","repo":"apache/iceberg","slug":"failed-to-acquire-zookeeper-lock-44102c","errorCode":null,"errorMessage":"Failed to acquire Zookeeper lock","messagePattern":"Failed to acquire Zookeeper lock","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/ZkLockFactory.java","lineNumber":218,"sourceCode":"    }\n\n    @Override\n    public boolean tryLock() {\n      VersionedValue<Integer> versionedValue = sharedCount.getVersionedValue();\n      if (isHeld(versionedValue)) {\n        LOG.debug(\"Lock is already held for path: {}\", lockPath);\n        return false;\n      }\n\n      try {\n        boolean acquired = sharedCount.trySetCount(versionedValue, LOCKED);\n        if (!acquired) {\n          LOG.debug(\"Failed to acquire lock for path: {}\", lockPath);\n        }\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","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/ZkLockFactory.java#L200-L236","documentation":"ZkLockFactory's lock (used by the Flink maintenance/rewrite commit coordinator) attempts to acquire a shared-count lock on a ZooKeeper path. Any exception during acquisition (connection loss, session expired, node errors) is caught, logged with this warning, and tryLock returns false rather than throwing. The caller should treat this as 'lock not acquired' and retry later.","triggerScenarios":"ZkLock.tryLock calls into Curator's SharedCount/lock APIs and catches Exception when ZooKeeper is unreachable, the session expires, or the lock path cannot be read/created.","commonSituations":"ZooKeeper ensemble restart or network partition during a maintenance trigger; session timeout too short for the job; ZK quorum loss.","solutions":["Check taskmanager logs for the accompanying stack trace to identify the ZooKeeper error (connection loss vs session expiry).","Verify ZooKeeper connectivity from the Flink cluster and ensure the ensemble is healthy.","Retry the maintenance job; tryLock is designed to fail soft and can succeed once ZK recovers.","Tune session/connection timeouts in the Curator client if transient expiries are frequent."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"boolean acquired = false;\nfor (int attempt = 0; attempt < 3 && !acquired; attempt++) {\n  acquired = lock.tryLock(); // returns false on ZK errors\n  if (!acquired) {\n    Thread.sleep(1000L * (attempt + 1));\n  }\n}\nif (!acquired) {\n  throw new IllegalStateException(\"Could not acquire Zookeeper lock after retries\");\n}","preventionTips":["Design callers to treat tryLock()==false as retryable, not fatal.","Monitor ZooKeeper ensemble health and session-expiry metrics.","Set session timeouts larger than the longest expected lock hold time."],"tags":["flink","zookeeper","lock","distributed-lock"],"backgroundTag":"lock-acquisition-failed","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"}