apache/iceberg · warning · IllegalStateException

Fail to acquire lock

Error message

Fail to acquire lock %s by %s, interrupted during sleep

What it means

IllegalStateException from DynamoDbLockManager.acquireOnce when the worker thread is interrupted while sleeping for the current lease duration before retrying the lock acquisition. The InterruptedException is chained as the cause. This prevents silently swallowing interruption signals during the bounded-retry acquire loop.

Solutions

  1. Let the exception propagate — treat interruption as a signal to stop lock acquisition
  2. If intentional, shut down/stop the job or executor that interrupted the worker before re-running
  3. Restore the interrupt flag if catching higher up (catch IllegalStateException, re-interrupt or abort)

Example fix

// before
try {
  future.get();
} catch (Exception e) {
  e.printStackTrace();
}
// after
try {
  future.get();
} catch (java.util.concurrent.ExecutionException e) {
  if (e.getCause() instanceof IllegalStateException
      && e.getCause().getCause() instanceof InterruptedException) {
    Thread.currentThread().interrupt(); // honor the interruption
  }
  throw new RuntimeException("Lock acquisition aborted", e);
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  lockManager.acquire(entityId, ownerId);
} catch (IllegalStateException e) {
  if (e.getCause() instanceof InterruptedException) {
    Thread.currentThread().interrupt(); // restore interrupt status
    throw e; // honor shutdown
  }
  throw e;
}

Prevention

When it happens

Trigger: acquireOnce loses the conditional put, reads the winner's lease-duration-ms and sleeps, and the thread is interrupted during Thread.sleep.

Common situations: Executor shutdown during task cancellation; application shutdown while a compaction/commit is waiting for a lock; test framework interrupting hung workers.

Related errors


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

Appendix: source

Thrown at aws/src/main/java/org/apache/iceberg/aws/dynamodb/DynamoDbLockManager.java:217

                .tableName(lockTableName)
                .consistentRead(true)
                .key(toKey(entityId))
                .build());

    if (!response.hasItem()) {
      dynamo.putItem(
          PutItemRequest.builder()
              .tableName(lockTableName)
              .item(toNewItem(entityId, ownerId, heartbeatTimeoutMs()))
              .conditionExpression(CONDITION_LOCK_ENTITY_NOT_EXIST)
              .build());
    } else {
      Map<String, AttributeValue> currentItem = response.item();

      try {
        Thread.sleep(Long.parseLong(currentItem.get(COL_LEASE_DURATION_MS).n()));
      } catch (InterruptedException e) {
        throw new IllegalStateException(
            String.format(
                "Fail to acquire lock %s by %s, interrupted during sleep", entityId, ownerId),
            e);
      }

      dynamo.putItem(
          PutItemRequest.builder()
              .tableName(lockTableName)
              .item(toNewItem(entityId, ownerId, heartbeatTimeoutMs()))
              .conditionExpression(CONDITION_LOCK_ENTITY_NOT_EXIST_OR_VERSION_MATCH)
              .expressionAttributeValues(
                  ImmutableMap.of(
                      ":eid", AttributeValue.builder().s(entityId).build(),
                      ":vid", AttributeValue.builder().s(currentItem.get(COL_VERSION).s()).build()))
              .build());
    }

    startNewHeartbeat(entityId, ownerId);

View on GitHub (pinned to 86d9c8fc54)