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
- Drop the existing table first or choose a new identifier
- Check catalog.tableExists(identifier) before registering and skip if present
- 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
- Check tableExists before registerTable
- Make migration scripts idempotent
- Use unique target identifiers per run or drop first
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
- Cannot create namespace %s: already exists
- Namespace already exists: %s
- View with same name already exists: %s
- Cannot rename table %s to %s: %s already exists
- Namespace already exists: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/24dc4365dee51e99.
Report an issue: GitHub.