apache/iceberg · error · org.apache.flink.table.api.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 creates a table loader and the target Iceberg database does not exist, it tries to create it with ignoreIfExists=false semantics via createDatabase; if the database was created concurrently (DatabaseAlreadyExistException), it rethrows as AlreadyExistsException. It signals a race or an existing database the existence pre-check missed.

Source

Thrown at flink/v2.1/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. Treat as benign if the database already exists — retry the query; the database is now present.
  2. Pre-create the database before submitting jobs (e.g. CREATE DATABASE IF NOT EXISTS in Flink SQL or via the Iceberg catalog API).
  3. Serialize job startup so concurrent writers don't race on database creation.

Example fix

// before (SQL, racing jobs)
CREATE TABLE iceberg_db.my_table ...; // each job auto-creates iceberg_db
// after
CREATE DATABASE IF NOT EXISTS iceberg_db;
CREATE TABLE iceberg_db.my_table ...;
Defensive patterns

Strategy: try-catch

Validate before calling

if (!flinkCatalog.databaseExists(dbName)) { /* pre-create once at deployment time */ }

Try / catch

try {
  flinkCatalog.createDatabase(db, new CatalogDatabaseImpl(Maps.newHashMap(), null), true);
} catch (DatabaseAlreadyExistException e) {
  // benign: another worker created it; proceed
}

Prevention

When it happens

Trigger: createTableLoader (invoked from createDynamicTableSource/createDynamicTableSink) when databaseExists(catalogDatabase) returned false but flinkCatalog.createDatabase then throws DatabaseAlreadyExistException — typically a concurrent job creating the same database.

Common situations: Multiple Flink jobs/queries starting simultaneously against a fresh Iceberg catalog and racing to create the same database; stale metadata in the factory's cached catalog view.

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/68ee7436c2913f99. Report an issue: GitHub.