{"record":{"id":"890b77d176c213d6","repo":"apache/hadoop","slug":"there-is-already-an-existing-lease-operation","errorCode":null,"errorMessage":"There is already an existing lease operation","messagePattern":"There is already an existing lease operation","errorType":"exception","errorClass":"LeaseException","httpStatus":null,"severity":"error","filePath":"hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsLease.java","lineNumber":180,"sourceCode":"  }\n\n  /**\n   * Acquire a lease on the given path.\n   *\n   * @param retryPolicy        Retry policy\n   * @param numRetries         Number of retries\n   * @param retryInterval      Retry interval in seconds\n   * @param delay              Delay in seconds\n   * @param eTag               ETag of the file\n   * @param tracingContext     Tracing context\n   * @throws LeaseException if the lease cannot be acquired\n   */\n  private void acquireLease(RetryPolicy retryPolicy, int numRetries,\n      int retryInterval, long delay, final String eTag, TracingContext tracingContext)\n      throws LeaseException {\n    LOG.debug(\"Attempting to acquire lease on {}, retry {}\", path, numRetries);\n    if (future != null && !future.isDone()) {\n      throw new LeaseException(ERR_LEASE_FUTURE_EXISTS);\n    }\n    FutureCallback<AbfsRestOperation> acquireCallback = new FutureCallback<AbfsRestOperation>() {\n      @Override\n      public void onSuccess(@Nullable AbfsRestOperation op) {\n        leaseID = op.getResult().getResponseHeader(HttpHeaderConfigurations.X_MS_LEASE_ID);\n        if (leaseRefreshDuration != INFINITE_LEASE_DURATION) {\n          leaseTimerTask = new LeaseTimerTask(client, path,\n                  leaseID, tracingContext);\n          timer.scheduleAtFixedRate(leaseTimerTask, leaseRefreshDuration / 2,\n                  leaseRefreshDuration / 2);\n        }\n        LOG.debug(\"Acquired lease {} on {}\", leaseID, path);\n      }\n\n      @Override\n      public void onFailure(Throwable throwable) {\n        try {\n          if (RetryPolicy.RetryAction.RetryDecision.RETRY","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsLease.java#L162-L198","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Wait for the in-flight acquisition to finish before retrying (poll the lease state / synchronize on the lease object)","Free the existing lease first, then acquire again, so future is done and state is clean","Serialize all lease operations per path through a single owner/thread","Catch LeaseException and back off instead of retrying immediately"],"exampleFix":"// before\ntry {\n  lease.acquire(...);          // may overlap a still-running acquire\n} catch (LeaseException e) {\n  lease.acquire(...);          // LeaseException: existing lease operation\n}\n\n// after\nsynchronized (lease) {\n  while (!lease.isFree()) {    // wait for prior future to complete\n    lease.wait(100);\n  }\n  lease.acquire(...);\n}","handlingStrategy":"retry","validationCode":"// Serialize lease acquisition per path; never overlap acquires\nsynchronized (leaseLock) {\n  while (acquireInFlight) {\n    try { leaseLock.wait(100); } catch (InterruptedException ie) {\n      Thread.currentThread().interrupt(); return;\n    }\n  }\n  acquireInFlight = true;\n}\ntry { lease.acquire(...); } finally {\n  synchronized (leaseLock) { acquireInFlight = false; leaseLock.notifyAll(); }\n}","typeGuard":null,"tryCatchPattern":"try {\n  lease.acquire(...);\n} catch (LeaseException e) {\n  if (e.getMessage().contains(\"already an existing lease operation\")) {\n    Thread.sleep(backoffMs);      // let the in-flight future finish\n    lease.acquire(...);           // then retry once\n  } else throw e;\n}","preventionTips":["One owner thread per lease — no concurrent acquire calls on the same handle","Free the lease before re-acquiring on recovery paths","Back off on acquisition failures instead of immediate tight retries"],"tags":["azure-blob","abfs","lease","concurrency","async"],"backgroundTag":"operation-already-in-progress","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}