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
- Catch CommitFailedException and treat it as 'table already exists'; proceed to load the existing table or fail gracefully.
- Check catalog.tableExists(identifier) before issuing the create commit.
- Use create-or-replace semantics (catalog.createTransaction/buildReplace) if overwrite is intended.
- 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
- Check tableExists before create; use create-or-replace when overwrite is intended.
- Expect concurrent creators; treat CommitFailedException on create as 'exists'.
- Avoid retry loops that blindly re-issue create after a failure.
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
- Cannot commit: stale table metadata
- Requirement failed: %s %s was created concurrently
- Requirement failed: %s %s has changed: expected id %s != %s
- Requirement failed: branch or tag %s is missing, expected %s
- Requirement failed: last assigned field id changed: expected
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/8a52d79002107417.
Report an issue: GitHub.