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

  1. 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.
  2. Resolve any concurrent migration of the same source table and retry once no other process is migrating it.
  3. 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

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


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)