apache/iceberg · error · AlreadyExistsException
Table already exists: %s.%s
Error message
Table already exists: %s.%s
What it means
HiveTableOperations.doCommit throws AlreadyExistsException 'Table already exists: %s.%s' when a create (newTable) commit finds an existing HMS entity that already has the Iceberg METADATA_LOCATION_PROP and is not a VIRTUAL_VIEW — a concurrent commit created the same table first. The commit fails rather than overwriting the other writer's table.
Source
Thrown at hive-metastore/src/main/java/org/apache/iceberg/hive/HiveTableOperations.java:286
boolean updateHiveTable = false;
HiveLock lock = lockObject(base != null ? base : tableMetadata);
try {
lock.lock();
Table tbl = loadHmsTable();
if (tbl != null) {
// If we try to create the table but the metadata location is already set, then we had a
// concurrent commit
if (newTable
&& tbl.getParameters().get(BaseMetastoreTableOperations.METADATA_LOCATION_PROP)
!= null) {
if (TableType.VIRTUAL_VIEW.name().equalsIgnoreCase(tbl.getTableType())) {
throw new AlreadyExistsException(
"View with same name already exists: %s.%s", database, tableName);
}
throw new AlreadyExistsException("Table already exists: %s.%s", database, tableName);
}
updateHiveTable = true;
LOG.debug("Committing existing table: {}", fullName);
} else {
tbl =
newHmsTable(
tableMetadata.property(HiveCatalog.HMS_TABLE_OWNER, HiveHadoopUtil.currentUser()));
LOG.debug("Committing new table: {}", fullName);
}
tbl.setSd(
HiveOperationsBase.storageDescriptor(
tableMetadata.schema(),
tableMetadata.location(),
hiveEngineEnabled)); // set to pickup any schema changes
String metadataLocation = tbl.getParameters().get(METADATA_LOCATION_PROP);View on GitHub (pinned to 86d9c8fc54)
Solutions
- Catch AlreadyExistsException and load the existing table instead of creating (create-if-absent semantics).
- Guard creation with an external lock or a check-then-create inside one orchestrator to prevent races.
- If the existing table is unwanted, drop it first and then create, ensuring no other writer is committing.
Example fix
// before Table t = catalog.createTable(ident, schema); // races with another writer // after Table t = catalog.tableExists(ident) ? catalog.loadTable(ident) : catalog.createTable(ident, schema);
Defensive patterns
Strategy: try-catch
Validate before calling
boolean exists = catalog.tableExists(ident); // create only when false, ideally behind a lock
Try / catch
try { table = catalog.createTable(ident, schema); } catch (AlreadyExistsException e) { table = catalog.loadTable(ident); } Prevention
- Adopt create-if-absent (load on AlreadyExists) for table initialization.
- Use external locking or a single writer for schema bootstrap.
- Avoid racing multi-engine initializations of the same table.
When it happens
Trigger: Two concurrent catalog.createTable calls for the same database.name: the loser reaches doCommit, HMS returns the existing table, and its metadata_location property is set (excluding a plain HMS leftover).
Common situations: Duplicate jobs creating the same table in parallel; orchestration retries racing; multi-engine setup where two frameworks initialize the same Iceberg table.
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
- View with same name already exists: %s.%s
- %s already exists: %s.%s
- View already exists: %s.%s
- Table already exists: %s
- View already exists: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/05dd6611bb25e8db.
Report an issue: GitHub.