apache/iceberg · error · org.apache.flink.table.catalog.exceptions.AlreadyExistsException
Table %s already exists in the database %s and catalog %s
Error message
Table %s already exists in the database %s and catalog %s
What it means
createTableLoader checks tableExists and then attempts createIcebergTable with ignoreIfExists semantics. If TableAlreadyExistException is thrown anyway (e.g., concurrent creation), it is wrapped into AlreadyExistsException with 'Table %s already exists in the database %s and catalog %s'.
Source
Thrown at flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/FlinkDynamicTableFactory.java:226
if (!flinkCatalog.databaseExists(catalogDatabase)) {
try {
flinkCatalog.createDatabase(
catalogDatabase, new CatalogDatabaseImpl(Maps.newHashMap(), null), true);
} catch (DatabaseAlreadyExistException e) {
throw new AlreadyExistsException(
e,
"Database %s already exists in the iceberg catalog %s.",
catalogName,
catalogDatabase);
}
}
// Create table if not exists in the external catalog.
if (!flinkCatalog.tableExists(objectPath)) {
try {
flinkCatalog.createIcebergTable(objectPath, resolvedCatalogTable, true);
} catch (TableAlreadyExistException e) {
throw new AlreadyExistsException(
e,
"Table %s already exists in the database %s and catalog %s",
catalogTable,
catalogDatabase,
catalogName);
}
}
return TableLoader.fromCatalog(
flinkCatalog.getCatalogLoader(), TableIdentifier.of(catalogDatabase, catalogTable));
}
/**
* Merges source catalog properties (catalog name, database, table) with connector properties.
* Source catalog name, database, table are serialized as json in FlinkCatalog#getTable to be able
* to isolate them from iceberg table props, Here, we flatten and merge them back.
*
* @param tableProps the existing table propertiesView on GitHub (pinned to 86d9c8fc54)
Solutions
- Check flinkCatalog.tableExists(objectPath) first and reuse the existing table
- Catch AlreadyExistsException and treat as success when the existing table matches your schema
- Serialize table creation via deployment orchestration
- Use unique table names per job/environment
Example fix
// before
flinkCatalog.createIcebergTable(objectPath, resolvedCatalogTable, true);
// after
if (!flinkCatalog.tableExists(objectPath)) {
flinkCatalog.createIcebergTable(objectPath, resolvedCatalogTable, true);
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!catalog.tableExists(objectPath)) { /* create */ } Try / catch
try { catalog.createIcebergTable(objectPath, tbl, true); } catch (TableAlreadyExistException | AlreadyExistsException e) { /* idempotent success */ } Prevention
- Check tableExists before creating
- Treat AlreadyExistsException as success when schema matches
- Serialize table creation in deployment pipelines
- Use unique table names per environment
When it happens
Trigger: Concurrent CREATE TABLE (or Flink dynamic table source/sink initialization) for the same Iceberg table from multiple jobs; check-then-create race between tableExists and createIcebergTable.
Common situations: Two streaming jobs writing to the same table path launched simultaneously; CI pipelines deploying the same job twice; shared dev catalogs where tables are created ad hoc.
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
- Table already exists: %s
- Database %s already exists in the iceberg catalog %s.
- Table %s already exists in the database %s and catalog %s
- Database %s already exists in the iceberg catalog %s.
- Table was created concurrently: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9de06fb776369a31.
Report an issue: GitHub.