apache/iceberg · error · IllegalStateException

Cannot find Dynamo table

Error message

Cannot find Dynamo table %s

What it means

IllegalStateException from DynamoDbLockManager.checkTableActive when DescribeTable raises ResourceNotFoundException, i.e. the configured lock table does not exist. Unlike other paths, the ResourceNotFound cause is discarded and rethrown as IllegalStateException.

Solutions

  1. Create the Dynamo lock table with the key schema DynamoDbLockManager expects (entityId hash key)
  2. Verify the table name property and the client region match where the table exists
  3. Check the AWS console/CloudTrail to see whether the table was deleted recently

Example fix

// before
LockManager lockManager = new DynamoDbLockManager(dynamo, "iceberg-locks");
// after
// create the table first (hash key: entityId)
dynamo.createTable(b -> b.tableName("iceberg-locks")
    .keySchema(k -> k.hashKey("entityId"))
    .attributeDefinitions(a -> a.attributeName("entityId").attributeType("S"))
    .billingMode(BillingMode.PAY_PER_REQUEST));
LockManager lockManager = new DynamoDbLockManager(dynamo, "iceberg-locks");
Defensive patterns

Strategy: validation

Validate before calling

boolean exists = dynamo.listTables().tableNames().contains(lockTableName);
if (!exists) {
  dynamo.createTable(b -> b.tableName(lockTableName)
      .keySchema(k -> k.hashKey("entityId"))
      .attributeDefinitions(a -> a.attributeName("entityId").attributeType("S"))
      .billingMode(BillingMode.PAY_PER_REQUEST));
}

Try / catch

try {
  lockManager.acquire(entityId, ownerId);
} catch (IllegalStateException e) {
  if (e.getMessage().contains("Cannot find Dynamo table")) {
    createLockTable(lockTableName); // provision then retry
  }
  throw e;
}

Prevention

When it happens

Trigger: acquire/release on a lock table name that does not exist in the current region/account.

Common situations: Lock table never created; typo in the table-name property; wrong AWS region configured so the table lookup hits the wrong partition; table deleted by lifecycle policy or another team.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

      dynamo.describeTable(DescribeTableRequest.builder().tableName(tableName).build());
      return true;
    } catch (ResourceNotFoundException e) {
      return false;
    }
  }

  private void checkTableActive(String tableName) {
    try {
      DescribeTableResponse response =
          dynamo.describeTable(DescribeTableRequest.builder().tableName(tableName).build());
      TableStatus currentStatus = response.table().tableStatus();
      if (!currentStatus.equals(TableStatus.ACTIVE)) {
        throw new IllegalStateException(
            String.format(
                "Dynamo table %s is not active, current status: %s", tableName, currentStatus));
      }
    } catch (ResourceNotFoundException e) {
      throw new IllegalStateException(String.format("Cannot find Dynamo table %s", tableName));
    }
  }

  @Override
  public void initialize(Map<String, String> properties) {
    super.initialize(properties);
    this.dynamo = AwsClientFactories.from(properties).dynamo();
    this.lockTableName = properties.get(CatalogProperties.LOCK_TABLE);
    Preconditions.checkNotNull(lockTableName, "DynamoDB lock table name must not be null");
    ensureLockTableExistsOrCreate();
  }

  @Override
  public boolean acquire(String entityId, String ownerId) {
    try {
      Tasks.foreach(entityId)
          .throwFailureWhenFinished()
          .retry(Integer.MAX_VALUE - 1)

View on GitHub (pinned to 86d9c8fc54)