apache/iceberg · error · org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException

Table already exists

Error message

Table already exists: %s

What it means

Spark's catalog API signals that a CREATE TABLE was issued for an identifier that already exists in the Iceberg catalog. SparkCatalog.createTable catches Iceberg's AlreadyExistsException from the underlying catalog's create() call and rethrows Spark's own org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException so Spark session/analysis layers handle it consistently.

Solutions

  1. Use CREATE TABLE IF NOT EXISTS, or check catalog.tableExists(ident) before creating.
  2. Wrap creation in try-catch on TableAlreadyExistsException and reuse the existing table.
  3. Drop the stale table first (DROP TABLE) if it is safe to recreate.
  4. Verify you are writing to the intended catalog/namespace (spark.sql.catalog.* configuration).

Example fix

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

Strategy: try-catch

Validate before calling

if (spark.catalog().tableExists("db", "events")) { /* reuse or skip */ }

Type guard

boolean isFresh = spark instanceof SparkSession s && !s.catalog().tableExists(ident.namespace(), ident.name());

Try / catch

try { catalog.createTable(ident, schema, transforms, props); } catch (TableAlreadyExistsException e) { table = catalog.loadTable(ident); }

Prevention

When it happens

Trigger: Calling CREATE TABLE (or DataFrameWriter.saveAsTable with mode ErrorIfExists/default) for an identifier that already exists; also CREATE TABLE without IF NOT EXISTS; the underlying icebergCatalog.create() throws AlreadyExistsException which is converted at line 267.

Common situations: Re-running a notebook or migration script that creates tables idempotently without IF NOT EXISTS; two jobs racing to create the same table; Spark session pointing at a catalog/namespace different from the one the developer assumed (table exists there); Hive vs Hadoop catalog confusion in multi-catalog setups.

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/9cf59c0e7f399b43. Report an issue: GitHub.

Appendix: source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java:267

    }
  }

  @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)