{"record":{"id":"4f66c9bb7b41473e","repo":"apache/iceberg","slug":"cannot-rename-s-as-s-for-backup-the-backup-tabl","errorCode":null,"errorMessage":"Cannot rename %s as %s for backup. The backup table already exists.","messagePattern":"Cannot rename (.+?) as (.+?) for backup\\. The backup table already exists\\.","errorType":"exception","errorClass":"AlreadyExistsException","httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/actions/MigrateTableSparkAction.java","lineNumber":242,"sourceCode":"    Preconditions.checkArgument(\n        catalog instanceof SparkSessionCatalog,\n        \"Cannot migrate a table from a non-Iceberg Spark Session Catalog. Found %s of class %s as the source catalog.\",\n        catalog.name(),\n        catalog.getClass().getName());\n\n    return (TableCatalog) catalog;\n  }\n\n  private void renameAndBackupSourceTable() {\n    try {\n      LOG.info(\"Renaming {} as {} for backup\", sourceTableIdent(), backupIdent);\n      destCatalog().renameTable(sourceTableIdent(), backupIdent);\n\n    } catch (org.apache.spark.sql.catalyst.analysis.NoSuchTableException e) {\n      throw new NoSuchTableException(\"Cannot find source table %s\", sourceTableIdent());\n\n    } catch (org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException e) {\n      throw new AlreadyExistsException(\n          \"Cannot rename %s as %s for backup. The backup table already exists.\",\n          sourceTableIdent(), backupIdent);\n    }\n  }\n\n  private void restoreSourceTable() {\n    try {\n      LOG.info(\"Restoring {} from {}\", sourceTableIdent(), backupIdent);\n      destCatalog().renameTable(backupIdent, sourceTableIdent());\n\n    } catch (org.apache.spark.sql.catalyst.analysis.NoSuchTableException e) {\n      LOG.error(\n          \"Cannot restore the original table, the backup table {} cannot be found\", backupIdent, e);\n\n    } catch (org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException e) {\n      LOG.error(\n          \"Cannot restore the original table, a table with the original name exists. \"\n              + \"Use the backup table {} to restore the original table manually.\",","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/actions/MigrateTableSparkAction.java#L224-L260","documentation":"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.'","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nspark.sql(\"CALL prod.system.migrate(table => 'db.events')\"); // fails again due to stale backup\n// after\nspark.sql(\"DROP TABLE prod.db.events_BACKUP__\"); // verify contents first\nspark.sql(\"CALL prod.system.migrate(table => 'db.events')\");","handlingStrategy":"validation","validationCode":"// Pre-check for stale backup tables before migrating (backup suffix pattern)\nval stale = spark.sessionState.catalog.listTables(new org.apache.spark.sql.catalyst.TableIdentifier(\"analytics\").database)\n// simpler SQL pre-check:\nspark.sql(s\"SHOW TABLES IN prod_catalog.analytics LIKE '*__BACKUP__*'\").show()","typeGuard":null,"tryCatchPattern":"try {\n  action.execute();\n} catch (org.apache.iceberg.exceptions.AlreadyExistsException e) {\n  LOG.error(\"A backup table from a prior run exists; inspect and drop or restore it: {}\", e.getMessage());\n}","preventionTips":["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."],"tags":["spark","migrate-table","already-exists","backup-table"],"backgroundTag":"file-already-exists","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}