apache/iceberg · error · AlreadyExistsException

Table already exists: %s

Error message

Table already exists: %s

What it means

registerTable attaches an existing metadata.json to a new identifier, but the catalog refuses to overwrite an existing table. It throws AlreadyExistsException when tableExists(identifier) is true, mirroring the REST/409 'already exists' convention.

Source

Thrown at core/src/main/java/org/apache/iceberg/BaseMetastoreCatalog.java:83

    } else {
      throw new NoSuchTableException("Invalid table identifier: %s", identifier);
    }

    LOG.info("Table loaded by catalog: {}", result);
    return result;
  }

  @Override
  public Table registerTable(TableIdentifier identifier, String metadataFileLocation) {
    Preconditions.checkArgument(
        identifier != null && isValidIdentifier(identifier), "Invalid identifier: %s", identifier);
    Preconditions.checkArgument(
        metadataFileLocation != null && !metadataFileLocation.isEmpty(),
        "Cannot register an empty metadata file location as a table");

    // Throw an exception if this table already exists in the catalog.
    if (tableExists(identifier)) {
      throw new AlreadyExistsException("Table already exists: %s", identifier);
    }

    TableOperations ops = newTableOps(identifier);
    InputFile metadataFile = ops.io().newInputFile(metadataFileLocation);
    TableMetadata metadata = TableMetadataParser.read(metadataFile);
    ops.commit(null, metadata);

    return new BaseTable(ops, fullTableName(name(), identifier), metricsReporter());
  }

  @Override
  public TableBuilder buildTable(TableIdentifier identifier, Schema schema) {
    return new BaseMetastoreCatalogTableBuilder(identifier, schema);
  }

  private Table loadMetadataTable(TableIdentifier identifier) {
    String tableName = identifier.name();
    MetadataTableType type = MetadataTableType.from(tableName);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Drop the existing table first or choose a new identifier
  2. Check catalog.tableExists(identifier) before registering and skip if present
  3. Make registration idempotent by catching AlreadyExistsException and verifying metadata equality

Example fix

// before
catalog.registerTable(ident, metadataLocation); // AlreadyExistsException on re-run
// after
if (!catalog.tableExists(ident)) {
  catalog.registerTable(ident, metadataLocation);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (catalog.tableExists(identifier)) { skip or fail fast; }

Try / catch

try { catalog.registerTable(ident, loc); } catch (AlreadyExistsException e) { logger.info("Table {} already registered, skipping", ident); }

Prevention

When it happens

Trigger: Calling catalog.registerTable(identifier, metadataFileLocation) where a table (or metadata table name collision) already exists at that identifier in this catalog.

Common situations: Re-running a migration/import script without drop or idempotency; registering into the wrong catalog where the name is taken; concurrent registration jobs.

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