apache/iceberg · error · org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException
TableAlreadyExistsException
Error message
TableAlreadyExistsException: <ident>
What it means
When SparkCatalog.createTable calls the underlying Iceberg catalog's create(), the catalog may reject the creation because a table (or its metadata file) already exists at that identifier, surfacing AlreadyExistsException. Spark translates this into Spark's TableAlreadyExistsException carrying the identifier.
Solutions
- Use CREATE TABLE IF NOT EXISTS if the table existing is acceptable.
- Drop the existing table first (DROP TABLE) if it should be recreated.
- Use CREATE OR REPLACE TABLE when intentional replacement is desired.
- If caused by orphan metadata files, clean the stale metadata at the table location before retrying.
Example fix
-- before CREATE TABLE catalog.db.t (id bigint) USING iceberg; -- throws if t exists -- after CREATE TABLE IF NOT EXISTS catalog.db.t (id bigint) USING iceberg;
Defensive patterns
Strategy: try-catch
Validate before calling
-- Spark SQL precheck SHOW TABLES IN catalog.db LIKE 't';
Try / catch
try {
spark.sql("CREATE TABLE catalog.db.t ... ");
} catch (TableAlreadyExistsException e) {
// idempotent path: skip or replace
spark.sql("CREATE TABLE IF NOT EXISTS catalog.db.t ...");
} Prevention
- Use IF NOT EXISTS in DDL scripts intended to be re-runnable
- Fully qualify catalog.namespace.table to avoid hitting an unintended catalog
- Coordinate concurrent DDL for the same identifier across jobs
- After failed creates, check for orphan metadata files at the target location
When it happens
Trigger: Executing CREATE TABLE (without IF NOT EXISTS / OR REPLACE) on an identifier that already exists in the Iceberg catalog, or a stale metadata file at the target location causing an AlreadyExistsException during commit.
Common situations: Rerunning idempotent-looking DDL scripts without IF NOT EXISTS; concurrent jobs creating the same table; leftover metadata files from a failed/aborted create at the same location.
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
- Cannot add column since setting default values in Spark is…
- Cannot create table as it already exists
- Cannot specify the 'identifier-fields' because it's a…
- Cannot specify the 'sort-order' because it's a reserved…
- does not support creating tables
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/717029be997bcd23.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java:219
}
}
@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);
} 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)