apache/iceberg · error · TableAlreadyExistsException
TableAlreadyExistsException(to)
Error message
TableAlreadyExistsException(to)
What it means
Spark's renameTable failed because the target identifier already exists in the underlying Iceberg catalog; the Iceberg AlreadyExistsException was caught and rethrown as Spark's TableAlreadyExistsException. Iceberg catalogs refuse to overwrite an existing table during rename.
Source
Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java:432
private boolean catalogDropTable(Identifier ident) {
if (isPathIdentifier(ident)) {
return tables.dropTable(((PathIdentifier) ident).location(), false /* don't purge data */);
} else {
return icebergCatalog.dropTable(buildIdentifier(ident), false /* don't purge data */);
}
}
@Override
public void renameTable(Identifier from, Identifier to)
throws NoSuchTableException, TableAlreadyExistsException {
try {
checkNotPathIdentifier(from, "renameTable");
checkNotPathIdentifier(to, "renameTable");
icebergCatalog.renameTable(buildIdentifier(from), buildIdentifier(to));
} catch (org.apache.iceberg.exceptions.NoSuchTableException e) {
throw new NoSuchTableException(from);
} catch (AlreadyExistsException e) {
throw new TableAlreadyExistsException(to);
}
}
@Override
public void invalidateTable(Identifier ident) {
if (!isPathIdentifier(ident)) {
icebergCatalog.invalidateTable(buildIdentifier(ident));
}
}
@Override
public Identifier[] listTables(String[] namespace) {
return icebergCatalog.listTables(Namespace.of(namespace)).stream()
.map(ident -> Identifier.of(ident.namespace().levels(), ident.name()))
.toArray(Identifier[]::new);
}
@OverrideView on GitHub (pinned to 86d9c8fc54)
Solutions
- Check target existence with spark.catalog().tableExists and drop or pick a different target name first.
- If a retry is expected, drop the target table before re-running the rename.
- Use unique, time-suffixed target names in automated pipelines.
- If the stale target is unwanted, remove it via the same Iceberg catalog (not just the metastore).
Example fix
// before
spark.sql("ALTER TABLE mydb.orders RENAME TO mydb.orders_v2") // TableAlreadyExistsException
// after
if (spark.catalog().tableExists("iceberg_catalog.mydb.orders_v2")) {
spark.sql("DROP TABLE iceberg_catalog.mydb.orders_v2")
}
spark.sql("ALTER TABLE iceberg_catalog.mydb.orders RENAME TO iceberg_catalog.mydb.orders_v2") Defensive patterns
Strategy: validation
Validate before calling
if (spark.catalog().tableExists("iceberg_catalog.mydb.orders_v2")) {
spark.sql("DROP TABLE iceberg_catalog.mydb.orders_v2");
} Try / catch
try {
catalog.renameTable(from, to);
} catch (TableAlreadyExistsException e) {
// target exists: drop it or choose another name, then retry once
} Prevention
- Check/drop target before rename
- Use unique time-suffixed target names in pipelines
- Make rename steps idempotent for retries
- Do not reuse backup names across runs without cleanup
When it happens
Trigger: ALTER TABLE from RENAME TO to where 'to' is an existing table; retried rename jobs where a previous attempt partially succeeded; creating a backup-name workflow that reuses an old target name without dropping it first.
Common situations: Idempotent pipelines that rerun renames; users expecting RENAME to overwrite like some engines do; schema-evolution scripts that cycle names (orders -> orders_old -> orders).
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 rename table %s to %s: %s already exists
- Cannot rename %s to %s. View already exists
- Cannot rename %s to %s. Table already exists
- Cannot rename %s to %s. Another content of type %s with same
- View already exists: toIdentifier
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/4576be2617a48475.
Report an issue: GitHub.