apache/iceberg · error · AlreadyExistsException

Cannot create table %s as it already exists

Error message

Cannot create table %s as it already exists

What it means

This error is thrown when a Spark table-creation action (e.g. snapshot/migrate) attempts to create the destination Iceberg table but the catalog reports the table already exists. The Spark catalyst TableAlreadyExistsException is translated into Iceberg's AlreadyExistsException with the destination identifier in the message.

Source

Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/actions/BaseTableCreationSparkAction.java:167

        SparkSessionCatalog.class.getName(),
        SparkCatalog.class.getName());

    return (StagingTableCatalog) catalog;
  }

  protected StagedSparkTable stageDestTable() {
    try {
      Map<String, String> props = destTableProps();
      return (StagedSparkTable)
          destCatalog()
              .stageCreate(
                  destTableIdent(),
                  Spark3Util.tableInfo(sourceTable.columns(), sourceTable.partitioning(), props));
    } catch (org.apache.spark.sql.catalyst.analysis.NoSuchNamespaceException e) {
      throw new NoSuchNamespaceException(
          "Cannot create table %s as the namespace does not exist", destTableIdent());
    } catch (org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException e) {
      throw new AlreadyExistsException(
          "Cannot create table %s as it already exists", destTableIdent());
    }
  }

  protected void ensureNameMappingPresent(Table table) {
    if (!table.properties().containsKey(TableProperties.DEFAULT_NAME_MAPPING)) {
      NameMapping nameMapping = MappingUtil.create(table.schema());
      String nameMappingJson = NameMappingParser.toJson(nameMapping);
      table.updateProperties().set(TableProperties.DEFAULT_NAME_MAPPING, nameMappingJson).commit();
    }
  }

  protected String getMetadataLocation(Table table) {
    String defaultValue =
        LocationUtil.stripTrailingSlash(table.location()) + "/" + ICEBERG_METADATA_FOLDER;
    return LocationUtil.stripTrailingSlash(
        table.properties().getOrDefault(TableProperties.WRITE_METADATA_LOCATION, defaultValue));
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Drop the existing destination table or choose a new destTableIdent for the action
  2. Check whether a previous migration run partially completed and finish or clean it up first
  3. Verify you are targeting the intended catalog and namespace to avoid a name collision

Example fix

// before: re-running same command
dropTable("db.my_table"); actions.migrateTable("db.my_table");
// after: use a fresh destination or drop first
spark.sql("DROP TABLE IF EXISTS catalog.db.my_table"); actions.migrateTable("db.my_table");
Defensive patterns

Strategy: try-catch

Validate before calling

boolean exists = catalog.tableExists(destIdent);
if (exists) { throw new IllegalStateException("Destination already exists: " + destIdent); }

Try / catch

try { action.execute(); } catch (AlreadyExistsException e) { /* drop or rename destTableIdent, then retry */ }

Prevention

When it happens

Trigger: Running a snapshot/migrate Spark action via stageDestTable when destTableIdent() already exists in destCatalog; e.g. re-running a partially completed migration where the destination table was created in a prior run.

Common situations: Re-running an interrupted MigrateTable/SnapshotTable action without dropping the partially created destination table; naming collision with an existing table in the target catalog/namespace.

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/22738f25f8a1a559. Report an issue: GitHub.