apache/iceberg · error · TableAlreadyExistsException

org.apache.iceberg.exceptions.AlreadyExistsException:

Error message

org.apache.iceberg.exceptions.AlreadyExistsException: 

What it means

SparkCatalog.createTable maps Iceberg's AlreadyExistsException (raised by the underlying catalog's TableBuilder.create() because an identifier or location already exists) to Spark's TableAlreadyExistsException. Spark raises it to the user as a TABLE_OR_VIEW_ALREADY_EXISTS-style failure.

Source

Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java:268

    }
  }

  @Override
  public Table createTable(
      Identifier ident, StructType schema, Transform[] transforms, Map<String, String> properties)
      throws TableAlreadyExistsException {
    Schema icebergSchema = SparkSchemaUtil.convert(schema);
    try {
      Catalog.TableBuilder builder = newBuilder(ident, icebergSchema);
      org.apache.iceberg.Table icebergTable =
          builder
              .withPartitionSpec(Spark3Util.toPartitionSpec(icebergSchema, transforms))
              .withLocation(properties.get("location"))
              .withProperties(Spark3Util.rebuildCreateProperties(properties))
              .create();
      return new SparkTable(icebergTable, !cacheEnabled);
    } catch (AlreadyExistsException e) {
      throw new TableAlreadyExistsException(ident);
    }
  }

  @Override
  public StagedTable stageCreate(
      Identifier ident, StructType schema, Transform[] transforms, Map<String, String> properties)
      throws TableAlreadyExistsException {
    Schema icebergSchema = SparkSchemaUtil.convert(schema);
    try {
      Catalog.TableBuilder builder = newBuilder(ident, icebergSchema);
      Transaction transaction =
          builder
              .withPartitionSpec(Spark3Util.toPartitionSpec(icebergSchema, transforms))
              .withLocation(properties.get("location"))
              .withProperties(Spark3Util.rebuildCreateProperties(properties))
              .createTransaction();
      return new StagedSparkTable(transaction);
    } catch (AlreadyExistsException e) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Use CREATE TABLE IF NOT EXISTS or stageCreateOrReplace semantics if replacement is intended.
  2. Check tableExists(ident) before creating in code that must be idempotent.
  3. If a different table legitimately occupies the location, choose a new location or drop the conflicting table first.
  4. Handle TableAlreadyExistsException in the caller when racing concurrent creates.

Example fix

// before
spark.sql("CREATE TABLE prod.db.events (id BIGINT) USING iceberg");
// after
spark.sql("CREATE TABLE IF NOT EXISTS prod.db.events (id BIGINT) USING iceberg");
Defensive patterns

Strategy: try-catch

Validate before calling

if (catalog.tableExists(ident)) {
  throw new IllegalArgumentException("Table already exists: " + ident);
}

Try / catch

try {
  spark.sql(createTableSql);
} catch (TableAlreadyExistsException e) {
  LOG.warn("Table {} already exists, skipping create", ident);
  return spark.table(ident.toString());
}

Prevention

When it happens

Trigger: CREATE TABLE catalog.db.name ... when the table already exists in the catalog, or when another table is already registered at the requested custom location.

Common situations: Re-running idempotent-looking DDL scripts; races between concurrent Spark jobs creating the same table; stale catalog metadata in V2 session catalogs.

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/86efe2a498e19b7e. Report an issue: GitHub.