apache/iceberg · error · org.apache.flink.table.catalog.exceptions.AlreadyExistsException
Database %s already exists in the iceberg catalog %s.
Error message
Database %s already exists in the iceberg catalog %s.
What it means
When FlinkDynamicTableFactory.createTableLoader initializes an Iceberg table, it auto-creates the database in the external catalog if missing. If FlinkCatalog.createDatabase still reports DatabaseAlreadyExistException (a race or a misreported existence check), it is rethrown as Flink's AlreadyExistsException with this message. It signals a concurrent creation or a stale existence check.
Source
Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/FlinkDynamicTableFactory.java:213
String catalogDatabase = flinkConf.get(FlinkCreateTableOptions.CATALOG_DATABASE, databaseName);
Preconditions.checkArgument(
catalogDatabase != null,
"Invalid database name: null. Set %s create table option or specify fully qualified table name.",
FlinkCreateTableOptions.CATALOG_DATABASE);
String catalogTable = flinkConf.get(FlinkCreateTableOptions.CATALOG_TABLE, tableName);
FlinkCatalog flinkCatalog = createCatalogLoader(mergedProps, catalogName);
ObjectPath objectPath = new ObjectPath(catalogDatabase, catalogTable);
// Create database if not exists in the external catalog.
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);View on GitHub (pinned to 86d9c8fc54)
Solutions
- Rerun the job — after the first creation succeeds, the existence check will pass and the error disappears.
- Serialize database creation: create the database explicitly once (e.g. via catalog DDL or the Iceberg catalog API) before launching concurrent jobs.
- Add retry-on-already-exists handling in your launcher so a race is treated as success.
Example fix
// before
flinkCatalog.createDatabase(catalogDatabase, new CatalogDatabaseImpl(Maps.newHashMap(), null), true);
// after
try {
flinkCatalog.createDatabase(catalogDatabase, new CatalogDatabaseImpl(Maps.newHashMap(), null), true);
} catch (AlreadyExistsException e) {
// ignore — database created concurrently
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!flinkCatalog.databaseExists(databaseName)) {
LOG.info("Creating iceberg database {}", databaseName);
} Type guard
null
Try / catch
try {
createDatabasesAndTables();
} catch (AlreadyExistsException e) {
LOG.warn("Database created concurrently; continuing", e);
} Prevention
- Create databases once in a serialized setup step before parallel job launches.
- Make launchers idempotent: treat already-exists as success.
- Avoid retry loops that hammer createDatabase concurrently.
When it happens
Trigger: Two jobs/statements creating the same iceberg database concurrently so databaseExists returns false but createDatabase collides; flinkCatalog.databaseExists returning false inconsistently.
Common situations: Parallel Flink SQL client sessions issuing CREATE CATALOG/DDL against the same iceberg catalog at once; retry storms after a failed submission.
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
- Table already exists: %s
- Table does not exist: %s
- Cannot commit to table %s metadata location from %s to %s be
- View already exists: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/a3790e53bfb49c1c.
Report an issue: GitHub.