{"record":{"id":"5e5c6ef1c906ee6b","repo":"apache/iceberg","slug":"failed-to-release-lock-for-path-5e5c6e","errorCode":null,"errorMessage":"Failed to release lock for path: {}","messagePattern":"Failed to release lock for path: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/ZkLockFactory.java","lineNumber":242,"sourceCode":"    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 =\n        (retryPolicy == null) ? ZKRetryPolicies.EXPONENTIAL_BACKOFF : retryPolicy;\n\n    switch (effectivePolicy) {\n      case ONE_TIME:\n        return new RetryOneTime(baseSleepTimeMs);\n\n      case N_TIME:\n        return new RetryNTimes(maxRetries, baseSleepTimeMs);\n\n      case BOUNDED_EXPONENTIAL_BACKOFF:","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/ZkLockFactory.java#L224-L260","documentation":"ZkLock.unlock sets the shared count to UNLOCKED to release the maintenance lock. If that ZooKeeper operation throws, the factory logs this warning with the lock path and then rethrows a RuntimeException('Failed to release lock'), so the failure is not swallowed and will surface in the operator/job.","triggerScenarios":"Calling ZkLock.unlock() when the ZooKeeper session is expired or connection is lost, so sharedCount.setCount(UNLOCKED) fails and the catch block logs and wraps the exception.","commonSituations":"Long-running rewrite commits outliving the ZK session timeout; network interruption between Flink task and ZooKeeper during lock release.","solutions":["Inspect the wrapped cause in the RuntimeException stack trace to confirm the ZooKeeper failure mode (session expired, connection loss).","Increase ZooKeeper session timeout so releases of long-held locks don't run on expired sessions.","Ensure the ZK ensemble is healthy; the lock will remain held until the session expires, so allow the session to lapse or repair connectivity before retrying.","Retry the maintenance job after ZK connectivity is restored."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  lock.unlock();\n} catch (RuntimeException e) {\n  LOG.warn(\"Unlock failed (lock will lapse with ZK session); will retry\", e);\n  scheduleUnlockRetry();\n}","preventionTips":["Keep ZK sessions alive long enough to cover the full locked operation including unlock.","Add retry/backoff around unlock since a failed release blocks other workers until session expiry.","Alert on 'Failed to release lock' — concurrent maintenance runs may stall."],"tags":["flink","zookeeper","lock","unlock"],"backgroundTag":"lock-release-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"}