apache/hadoop · error · LeaseException

There is already an existing lease operation

Error message

There is already an existing lease operation

What it means

AbfsLease.acquireLease throws LeaseException("There is already an existing lease operation") when a previous async acquisition Future is still in flight (future != null && !future.isDone()). The class enforces one outstanding acquire per lease object because the callback writes shared state (leaseID, timer task), so overlapping acquires are rejected up front.

Solutions

  1. Wait for the in-flight acquisition to finish before retrying (poll the lease state / synchronize on the lease object)
  2. Free the existing lease first, then acquire again, so future is done and state is clean
  3. Serialize all lease operations per path through a single owner/thread
  4. Catch LeaseException and back off instead of retrying immediately

Example fix

// before
try {
  lease.acquire(...);          // may overlap a still-running acquire
} catch (LeaseException e) {
  lease.acquire(...);          // LeaseException: existing lease operation
}

// after
synchronized (lease) {
  while (!lease.isFree()) {    // wait for prior future to complete
    lease.wait(100);
  }
  lease.acquire(...);
}
Defensive patterns

Strategy: retry

Validate before calling

// Serialize lease acquisition per path; never overlap acquires
synchronized (leaseLock) {
  while (acquireInFlight) {
    try { leaseLock.wait(100); } catch (InterruptedException ie) {
      Thread.currentThread().interrupt(); return;
    }
  }
  acquireInFlight = true;
}
try { lease.acquire(...); } finally {
  synchronized (leaseLock) { acquireInFlight = false; leaseLock.notifyAll(); }
}

Try / catch

try {
  lease.acquire(...);
} catch (LeaseException e) {
  if (e.getMessage().contains("already an existing lease operation")) {
    Thread.sleep(backoffMs);      // let the in-flight future finish
    lease.acquire(...);           // then retry once
  } else throw e;
}

Prevention

When it happens

Trigger: Triggering acquireLease twice on the same AbfsLease before the first async acquire completes — e.g., a retry loop that immediately re-invokes on timeout, or two threads racing to (re)acquire the lease on the same path/lease handle.

Common situations: Hand-rolled retry logic around lease acquisition; concurrent writers each trying to acquire the lease object; recovery code that re-acquires after failure without waiting for the prior attempt's future to finish.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/890b77d176c213d6. Report an issue: GitHub.

Appendix: source

Thrown at hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsLease.java:180

  }

  /**
   * Acquire a lease on the given path.
   *
   * @param retryPolicy        Retry policy
   * @param numRetries         Number of retries
   * @param retryInterval      Retry interval in seconds
   * @param delay              Delay in seconds
   * @param eTag               ETag of the file
   * @param tracingContext     Tracing context
   * @throws LeaseException if the lease cannot be acquired
   */
  private void acquireLease(RetryPolicy retryPolicy, int numRetries,
      int retryInterval, long delay, final String eTag, TracingContext tracingContext)
      throws LeaseException {
    LOG.debug("Attempting to acquire lease on {}, retry {}", path, numRetries);
    if (future != null && !future.isDone()) {
      throw new LeaseException(ERR_LEASE_FUTURE_EXISTS);
    }
    FutureCallback<AbfsRestOperation> acquireCallback = new FutureCallback<AbfsRestOperation>() {
      @Override
      public void onSuccess(@Nullable AbfsRestOperation op) {
        leaseID = op.getResult().getResponseHeader(HttpHeaderConfigurations.X_MS_LEASE_ID);
        if (leaseRefreshDuration != INFINITE_LEASE_DURATION) {
          leaseTimerTask = new LeaseTimerTask(client, path,
                  leaseID, tracingContext);
          timer.scheduleAtFixedRate(leaseTimerTask, leaseRefreshDuration / 2,
                  leaseRefreshDuration / 2);
        }
        LOG.debug("Acquired lease {} on {}", leaseID, path);
      }

      @Override
      public void onFailure(Throwable throwable) {
        try {
          if (RetryPolicy.RetryAction.RetryDecision.RETRY

View on GitHub (pinned to 2add963021)