apache/iceberg · error · org.apache.flink.table.catalog.exceptions.AlreadyExistsException

Table already exists in the database and catalog

Error message

Table %s already exists in the database %s and catalog %s

What it means

During CREATE TABLE handling, FlinkDynamicTableFactory.createTableLoader tries to create the Iceberg table if it does not exist. If the creation races with another writer (or the existence check is stale), Flink throws TableAlreadyExistException which is wrapped as AlreadyExistsException with this message. It means the requested iceberg table already exists in the database/catalog.

Solutions

  1. Check whether the table already exists (SHOW TABLES / tableExists) before creating, or make creation idempotent.
  2. Catch AlreadyExistsException and treat it as success if your workflow expects the table to potentially exist.
  3. Create the table once out-of-band (e.g. via Spark/iceberg DDL) and have Flink only read/write it.

Example fix

// before
flinkCatalog.createIcebergTable(objectPath, resolvedCatalogTable, true);
// after
if (!flinkCatalog.tableExists(objectPath)) {
  try { flinkCatalog.createIcebergTable(objectPath, resolvedCatalogTable, true); }
  catch (TableAlreadyExistException e) { /* treat as success */ }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (flinkCatalog.tableExists(new ObjectPath(databaseName, tableName))) {
  LOG.info("Table {}.{} already exists; skipping create", databaseName, tableName);
}

Type guard

null

Try / catch

try {
  submitCreateTable();
} catch (AlreadyExistsException e) {
  LOG.info("Table already exists; treating as success", e);
}

Prevention

When it happens

Trigger: Submitting a CREATE TABLE (or a source/sink DDL with implicit create) for a table that already exists in the Iceberg catalog; two concurrent jobs creating the same table; ignoreIfExists semantics colliding.

Common situations: Re-running the same Flink SQL statement twice; CI pipelines submitting DDL idempotently without IF NOT EXISTS; multiple executors racing during job 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/d981307b718514ba. Report an issue: GitHub.

Appendix: source

Thrown at flink/v1.20/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)