apache/iceberg · error · AlreadyExistsException
Cannot rename as for backup. The backup table already…
Error message
Cannot rename %s as %s for backup. The backup table already exists.
What it means
During migrateTable, the action renames the source table to a generated backup identifier before building the Iceberg table. Spark's catalog threw TableAlreadyExistsException, meaning a table with the backup name already exists, so the action throws Iceberg's AlreadyExistsException: 'Cannot rename %s as %s for backup.'
Solutions
- Check for and drop the stale backup table (SHOW TABLES IN <catalog>.<db> LIKE '*BACKUP__*'; DROP TABLE <backup>) after confirming it is not needed, then re-run migrate.
- Resolve any concurrent migration of the same source table and retry once no other process is migrating it.
- If the backup table actually holds the migrated data from a prior partial run, follow the recovery path (restore/rename back) instead of deleting blindly.
Example fix
// before
spark.sql("CALL prod.system.migrate(table => 'db.events')"); // fails again due to stale backup
// after
spark.sql("DROP TABLE prod.db.events_BACKUP__"); // verify contents first
spark.sql("CALL prod.system.migrate(table => 'db.events')"); Defensive patterns
Strategy: validation
Validate before calling
// Pre-check for stale backup tables before migrating (backup suffix pattern)
val stale = spark.sessionState.catalog.listTables(new org.apache.spark.sql.catalyst.TableIdentifier("analytics").database)
// simpler SQL pre-check:
spark.sql(s"SHOW TABLES IN prod_catalog.analytics LIKE '*__BACKUP__*'").show() Try / catch
try {
action.execute();
} catch (org.apache.iceberg.exceptions.AlreadyExistsException e) {
LOG.error("A backup table from a prior run exists; inspect and drop or restore it: {}", e.getMessage());
} Prevention
- After any failed migration, immediately inspect and clean up *BACKUP__ tables before re-running.
- Never run two migrations of the same source table concurrently.
- Make migration recovery (restore or drop backup) an explicit, logged manual step.
When it happens
Trigger: Re-running migrate() after a previously failed/interrupted migration left the backup table behind (backup ident is derived from the source name, e.g. table_BACKUP__), so renameTable collides with the stale backup table.
Common situations: A previous migrate attempt crashed after rename but before commit; a leftover backup table from an earlier run; another concurrent migration of the same source 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
- Cannot rename as for backup. The backup table already…
- Cannot create table as it already exists
- Cannot find source table
- Cannot find source table
- Cannot rename as for backup. The backup table already…
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/4f66c9bb7b41473e.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/actions/MigrateTableSparkAction.java:242
Preconditions.checkArgument(
catalog instanceof SparkSessionCatalog,
"Cannot migrate a table from a non-Iceberg Spark Session Catalog. Found %s of class %s as the source catalog.",
catalog.name(),
catalog.getClass().getName());
return (TableCatalog) catalog;
}
private void renameAndBackupSourceTable() {
try {
LOG.info("Renaming {} as {} for backup", sourceTableIdent(), backupIdent);
destCatalog().renameTable(sourceTableIdent(), backupIdent);
} catch (org.apache.spark.sql.catalyst.analysis.NoSuchTableException e) {
throw new NoSuchTableException("Cannot find source table %s", sourceTableIdent());
} catch (org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException e) {
throw new AlreadyExistsException(
"Cannot rename %s as %s for backup. The backup table already exists.",
sourceTableIdent(), backupIdent);
}
}
private void restoreSourceTable() {
try {
LOG.info("Restoring {} from {}", sourceTableIdent(), backupIdent);
destCatalog().renameTable(backupIdent, sourceTableIdent());
} catch (org.apache.spark.sql.catalyst.analysis.NoSuchTableException e) {
LOG.error(
"Cannot restore the original table, the backup table {} cannot be found", backupIdent, e);
} catch (org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException e) {
LOG.error(
"Cannot restore the original table, a table with the original name exists. "
+ "Use the backup table {} to restore the original table manually.",View on GitHub (pinned to 86d9c8fc54)