apache/iceberg · error

Failed to release lock for path: {}

Error message

Failed to release lock for path: {}

What it means

ZkLock.unlock() sets the SharedCount back to UNLOCKED (0); if that ZK write throws, the warning "Failed to release lock for path: {}" is logged and a RuntimeException("Failed to release lock", e) is thrown to the caller. Unlike tryLock (which swallows), release failures are propagated because a stuck lock would block all future maintenance triggers for that table.

Source

Thrown at flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/ZkLockFactory.java:242

    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 =
        (retryPolicy == null) ? ZKRetryPolicies.EXPONENTIAL_BACKOFF : retryPolicy;

    switch (effectivePolicy) {
      case ONE_TIME:
        return new RetryOneTime(baseSleepTimeMs);

      case N_TIME:
        return new RetryNTimes(maxRetries, baseSleepTimeMs);

      case BOUNDED_EXPONENTIAL_BACKOFF:

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Restore ZooKeeper connectivity/session, then release the lock (unlock retries the setCount(UNLOCKED) write)
  2. Check the exception cause for KeeperException.Code (SESSIONEXPIRED vs CONNECTIONLOSS vs NOAUTH) to pick the right remedy
  3. Fix ZK ACLs if NOAUTH — the Flink user must have write access to /iceberg/flink/maintenance/locks/<lockId>
  4. If the lock remains stuck at LOCKED after recovery, manually reset the znode count to 0 (or delete it) and make lockIds unique per job
  5. Increase retry-policy retries so transient connection loss is retried inside setCount

Example fix

// before: unlock failure kills the maintenance task without cleanup
try {
  lock.unlock();
} catch (RuntimeException e) {
  throw e;
}

// after: retry release on transient connection loss before giving up
try {
  lock.unlock();
} catch (RuntimeException e) {
  if (isRetryableKeeperException(e.getCause())) { // e.g. CONNECTIONLOSS
    Thread.sleep(retryBackoffMs);
    lock.unlock();
  } else {
    throw e;
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// check lock state and ZK session before attempting release
if (lock.isHeld()) {
  client.getZookeeperClient().blockUntilConnectedOrTimedOut();
  lock.unlock();
}

Try / catch

try {
  lock.unlock();
} catch (RuntimeException e) {
  Throwable cause = e.getCause();
  if (cause instanceof org.apache.zookeeper.KeeperException
      && isRetryable((org.apache.zookeeper.KeeperException) cause)) { // CONNECTIONLOSS
    retryUnlockWithBackoff(lock);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling unlock() while the Curator session is expired/disconnected so setCount(0) cannot reach ZooKeeper; KeeperException (CONNECTIONLOSS, SESSIONEXPIRED, NOAUTH) during the ZK write; the shared count znode was deleted externally; interrupt during the ZK operation.

Common situations: ZooKeeper restart or failover while a maintenance task is releasing the lock; network blip between Flink and ZK during unlock; ZK ACL change removing write access to the lock path; task cancellation racing with session expiry.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/09c58fb57bef86f4. Report an issue: GitHub.