apache/iceberg · error · 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 creating a dynamic table source/sink, FlinkDynamicTableFactory auto-creates the database in the Iceberg catalog with ignoreIfExists=true; if createDatabase still reports DatabaseAlreadyExistException, it is rethrown as AlreadyExistsException with this message — indicating a race or inconsistent existence check.

Source

Thrown at flink/v2.2/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

  1. Retry the operation; the database now exists and the second attempt will succeed
  2. Serialize database/table bootstrap steps in deployment (one job creates schema first)
  3. Treat AlreadyExistsException as benign and proceed with loading the table loader

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) {
  // concurrent creation; database exists, continue
}
Defensive patterns

Strategy: retry

Validate before calling

if (catalog.databaseExists(dbName)) { /* skip creation */ }

Try / catch

try { loader.open(); } catch (AlreadyExistsException e) { /* concurrent creation; retry or proceed */ }

Prevention

When it happens

Trigger: createTableLoader runs, databaseExists returns false, then createDatabase races with another job/connection that creates the same database concurrently.

Common situations: Multiple Flink jobs starting simultaneously against the same Iceberg catalog, creating the same database namespace concurrently.

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/60862fd14cc2b061. Report an issue: GitHub.