apache/iceberg · error · AlreadyExistsException
Cannot create table %s as it already exists
Error message
Cannot create table %s as it already exists
What it means
This error is thrown when a Spark table-creation action (e.g. snapshot/migrate) attempts to create the destination Iceberg table but the catalog reports the table already exists. The Spark catalyst TableAlreadyExistsException is translated into Iceberg's AlreadyExistsException with the destination identifier in the message.
Source
Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/actions/BaseTableCreationSparkAction.java:167
SparkSessionCatalog.class.getName(),
SparkCatalog.class.getName());
return (StagingTableCatalog) catalog;
}
protected StagedSparkTable stageDestTable() {
try {
Map<String, String> props = destTableProps();
return (StagedSparkTable)
destCatalog()
.stageCreate(
destTableIdent(),
Spark3Util.tableInfo(sourceTable.columns(), sourceTable.partitioning(), props));
} catch (org.apache.spark.sql.catalyst.analysis.NoSuchNamespaceException e) {
throw new NoSuchNamespaceException(
"Cannot create table %s as the namespace does not exist", destTableIdent());
} catch (org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException e) {
throw new AlreadyExistsException(
"Cannot create table %s as it already exists", destTableIdent());
}
}
protected void ensureNameMappingPresent(Table table) {
if (!table.properties().containsKey(TableProperties.DEFAULT_NAME_MAPPING)) {
NameMapping nameMapping = MappingUtil.create(table.schema());
String nameMappingJson = NameMappingParser.toJson(nameMapping);
table.updateProperties().set(TableProperties.DEFAULT_NAME_MAPPING, nameMappingJson).commit();
}
}
protected String getMetadataLocation(Table table) {
String defaultValue =
LocationUtil.stripTrailingSlash(table.location()) + "/" + ICEBERG_METADATA_FOLDER;
return LocationUtil.stripTrailingSlash(
table.properties().getOrDefault(TableProperties.WRITE_METADATA_LOCATION, defaultValue));
}View on GitHub (pinned to 86d9c8fc54)
Solutions
- Drop the existing destination table or choose a new destTableIdent for the action
- Check whether a previous migration run partially completed and finish or clean it up first
- Verify you are targeting the intended catalog and namespace to avoid a name collision
Example fix
// before: re-running same command
dropTable("db.my_table"); actions.migrateTable("db.my_table");
// after: use a fresh destination or drop first
spark.sql("DROP TABLE IF EXISTS catalog.db.my_table"); actions.migrateTable("db.my_table"); Defensive patterns
Strategy: try-catch
Validate before calling
boolean exists = catalog.tableExists(destIdent);
if (exists) { throw new IllegalStateException("Destination already exists: " + destIdent); } Try / catch
try { action.execute(); } catch (AlreadyExistsException e) { /* drop or rename destTableIdent, then retry */ } Prevention
- Check catalog.tableExists(destIdent) before running snapshot/migrate actions
- Use unique destination identifiers per run or clean up after failed runs
- Inspect prior failed migrations for leftover destination tables
When it happens
Trigger: Running a snapshot/migrate Spark action via stageDestTable when destTableIdent() already exists in destCatalog; e.g. re-running a partially completed migration where the destination table was created in a prior run.
Common situations: Re-running an interrupted MigrateTable/SnapshotTable action without dropping the partially created destination table; naming collision with an existing table in the target catalog/namespace.
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
- org.apache.iceberg.exceptions.AlreadyExistsException:
- AS OF is not supported for changelogs
- Unknown Spark table type:
- Cannot specify the 'sort-order' because it's a reserved tabl
- Cannot specify the 'identifier-fields' because it's a reserv
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/22738f25f8a1a559.
Report an issue: GitHub.