apache/iceberg · error · org.apache.flink.table.api.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

FlinkDynamicTableFactory attempts to create the Iceberg table in the external catalog if tableExists says it is absent; if createIcebergTable then throws TableAlreadyExistException (the table appeared concurrently or the check was stale), it rethrows as AlreadyExistsException. It reports that the requested table already exists in the given database and catalog.

Source

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

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Verify the existing table's schema matches what you intended; if so, just use it — retry the query.
  2. Drop or rename the existing table if it was created with the wrong schema (DROP TABLE ... then resubmit).
  3. Gate table creation in your deployment pipeline (create once, then start jobs) to avoid the race.

Example fix

// before
CREATE TABLE catalog.db.events (...); // two jobs racing
// after
// job A: create table once; job B just reads/writes
CREATE TABLE IF NOT EXISTS catalog.db.events (...);
Defensive patterns

Strategy: try-catch

Validate before calling

if (flinkCatalog.tableExists(objectPath)) { /* skip creation; verify schema instead */ }

Try / catch

try {
  flinkCatalog.createIcebergTable(objectPath, table, true);
} catch (TableAlreadyExistException e) {
  // table exists: compare schemas and proceed if compatible
}

Prevention

When it happens

Trigger: createTableLoader (via createDynamicTableSource/createDynamicTableSink) when tableExists(objectPath) is false but flinkCatalog.createIcebergTable(objectPath, resolvedCatalogTable, true) throws TableAlreadyExistException.

Common situations: Two Flink jobs submitting the same new table concurrently; schema-evolution statements resubmitted in a retry loop; a sink and a source job both creating the table on startup.

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