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

MigrateTableSparkAction fails when it tries to rename the source table to its backup identifier and the backup identifier already exists in the destination catalog (TableAlreadyExistsException), reported as AlreadyExistsException.

Solutions

  1. Drop the existing backup table (after verifying it is disposable): DROP TABLE db.tbl_BACKUP__
  2. Restore the previous backup as the source if the earlier run failed, then re-run migration
  3. Use .backupTableName("unique_name") to pick a fresh backup identifier

Example fix

// before
SparkActions.get(spark).migrateTable("db.tbl").execute(); // db.tbl_BACKUP__ exists
// after
SparkActions.get(spark).migrateTable("db.tbl")
    .backupTableName("db.tbl_backup_20260911").execute();
Defensive patterns

Strategy: try-catch

Validate before calling

if (spark.catalog().tableExists(backupIdentString)) { dropBackupOrChooseAlternateName(); }

Try / catch

try { action.execute(); } catch (AlreadyExistsException e) { /* drop stale backup or set .backupTableName(newName) and retry */ }

Prevention

When it happens

Trigger: doExecute -> renameAndBackupSourceTable: destCatalog().renameTable(sourceTableIdent, backupIdent) where a table already occupies the backup name (default: sourceIdent + "_BACKUP__").

Common situations: Re-running a migration after a previous attempt failed post-rename; manually created table with the _BACKUP__ suffix; stale backup table never cleaned up.

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/04c73b3d47917c06. Report an issue: GitHub.

Appendix: source

Thrown at spark/v4.0/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)