apache/iceberg · error · CommitFailedException

Requirement failed: table already exists

Error message

Requirement failed: table already exists

What it means

AssertTableDoesNotExist is a commit requirement for table creation. During a commit, if a non-null base TableMetadata is returned (meaning the table already exists in the catalog), validate throws CommitFailedException so the create-table operation fails cleanly instead of overwriting.

Source

Thrown at core/src/main/java/org/apache/iceberg/UpdateRequirement.java:44

/** Represents a requirement for a {@link MetadataUpdate} */
public interface UpdateRequirement {
  default void validate(TableMetadata base) {
    throw new ValidationException(
        "Cannot validate %s against a table", this.getClass().getSimpleName());
  }

  default void validate(ViewMetadata base) {
    throw new ValidationException(
        "Cannot validate %s against a view", this.getClass().getSimpleName());
  }

  class AssertTableDoesNotExist implements UpdateRequirement {
    public AssertTableDoesNotExist() {}

    @Override
    public void validate(TableMetadata base) {
      if (base != null) {
        throw new CommitFailedException("Requirement failed: table already exists");
      }
    }
  }

  class AssertTableUUID implements UpdateRequirement {
    private final String uuid;

    public AssertTableUUID(String uuid) {
      Preconditions.checkArgument(uuid != null, "Invalid required UUID: null");
      this.uuid = uuid;
    }

    public String uuid() {
      return uuid;
    }

    @Override
    public void validate(TableMetadata base) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Catch CommitFailedException and treat it as 'table already exists'; proceed to load the existing table or fail gracefully.
  2. Check catalog.tableExists(identifier) before issuing the create commit.
  3. Use create-or-replace semantics (catalog.createTransaction/buildReplace) if overwrite is intended.
  4. Resolve concurrent creators via a single coordinator or unique table names.

Example fix

// before
table = catalog.buildTable(ident, schema).create(); // CommitFailedException if exists

// after
try {
  table = catalog.buildTable(ident, schema).create();
} catch (CommitFailedException e) {
  table = catalog.loadTable(ident); // already created concurrently
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (catalog.tableExists(identifier)) { /* load existing or use replace semantics */ }

Try / catch

try { catalog.buildTable(ident, schema).create(); } catch (CommitFailedException e) { /* table already exists: load or abort */ }

Prevention

When it happens

Trigger: Issuing a create-table commit (with AssertTableDoesNotExist requirement) to a catalog where a table with that identifier already exists.

Common situations: Concurrent create attempts of the same table; retrying a create that previously succeeded; not checking catalog existence before create; metastores with eventual consistency returning stale null.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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