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

During dynamic table creation, FlinkDynamicTableFactory.createTableLoader tries to create the database in the external catalog with ignoreIfNotExists semantics. If createDatabase nevertheless throws DatabaseAlreadyExistException (race with another job/client), it is converted to AlreadyExistsException with 'Database %s already exists in the iceberg catalog %s.'

Source

Thrown at flink/v2.3/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. Verify the database exists and reuse it instead of creating it
  2. Serialize database creation (create once via a setup job or catalog CLI) before submitting jobs
  3. Catch AlreadyExistsException and treat it as success if the database is the one you intended
  4. Use distinct database names per environment/team to avoid collisions

Example fix

// before
flinkCatalog.createDatabase(db, new CatalogDatabaseImpl(new HashMap<>(), null), true);

// after
if (!flinkCatalog.databaseExists(db)) {
  try {
    flinkCatalog.createDatabase(db, new CatalogDatabaseImpl(new HashMap<>(), null), true);
  } catch (DatabaseAlreadyExistException e) {
    // another client created it concurrently; safe to proceed
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!catalog.databaseExists(db)) { /* create */ }

Try / catch

try { catalog.createDatabase(db, new CatalogDatabaseImpl(new HashMap<>(), null), true); } catch (DatabaseAlreadyExistException | AlreadyExistsException e) { /* idempotent success */ }

Prevention

When it happens

Trigger: Two concurrent Flink jobs/queries both creating the same database via CREATE TABLE IF NOT EXISTS paths; a race where the database is created between the databaseExists check and createDatabase call.

Common situations: Parallel job deployments against a shared REST/Hive catalog; retrying a failed deployment while another client already created the database; sandbox namespaces shared across teams.

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/281947fa6204770c. Report an issue: GitHub.