apache/iceberg · error · AlreadyExistsException
Cannot rename %s to %s. Table already exists
Error message
Cannot rename %s to %s. Table already exists
What it means
renameTableOrView() throws AlreadyExistsException when a table already exists at the rename destination identifier. Hive requires unique table names per database, so renaming onto an existing table would clobber it and is refused.
Source
Thrown at hive-metastore/src/main/java/org/apache/iceberg/hive/HiveCatalog.java:406
.collect(Collectors.toList());
}
@SuppressWarnings("checkstyle:CyclomaticComplexity")
private void renameTableOrView(
TableIdentifier from,
TableIdentifier originalTo,
HiveOperationsBase.ContentType contentType) {
Preconditions.checkArgument(isValidIdentifier(from), "Invalid identifier: %s", from);
TableIdentifier to = removeCatalogName(originalTo);
Preconditions.checkArgument(isValidIdentifier(to), "Invalid identifier: %s", to);
if (!namespaceExists(to.namespace())) {
throw new NoSuchNamespaceException(
"Cannot rename %s to %s. Namespace does not exist: %s", from, to, to.namespace());
}
if (tableExists(to)) {
throw new AlreadyExistsException("Cannot rename %s to %s. Table already exists", from, to);
}
if (viewExists(to)) {
throw new AlreadyExistsException("Cannot rename %s to %s. View already exists", from, to);
}
String toDatabase = to.namespace().level(0);
String fromDatabase = from.namespace().level(0);
String fromName = from.name();
try {
Table table = clients.run(client -> client.getTable(fromDatabase, fromName));
validateTableIsIcebergTableOrView(contentType, table, CatalogUtil.fullTableName(name, from));
table.setDbName(toDatabase);
table.setTableName(to.name());
clients.run(View on GitHub (pinned to 86d9c8fc54)
Solutions
- Check catalog.tableExists(to) before renaming and pick a free destination name.
- Drop or rename the conflicting destination table if it is stale and safe to remove.
- Make destination names unique (add timestamp/suffix) in concurrent workflows.
- Beware Hive's case-insensitive matching — check variants of the destination name.
Example fix
// before
catalog.renameTable(from, TableIdentifier.of(db, "events"));
// after
TableIdentifier to = TableIdentifier.of(db, "events");
if (catalog.tableExists(to)) {
throw new IllegalStateException("Destination already exists: " + to);
}
catalog.renameTable(from, to); Defensive patterns
Strategy: validation
Validate before calling
TableIdentifier to = TableIdentifier.of(db, "events");
if (catalog.tableExists(to)) {
throw new IllegalStateException("Rename target already exists: " + to);
}
catalog.renameTable(from, to); Try / catch
try {
catalog.renameTable(from, to);
} catch (AlreadyExistsException e) {
// pick a new destination name or resolve the conflict manually
throw e;
} Prevention
- Always check tableExists on the destination before renaming.
- Remember Hive name matching is case-insensitive; check name variants.
- Use unique suffixes for generated destination names in concurrent pipelines.
When it happens
Trigger: Calling catalog.renameTable(from, to) (or renameView, which shares this path) where a table named to.name() already exists in to.namespace().
Common situations: Renaming to a name that was previously used and never cleaned up; concurrent job created the destination table first; retrying a rename that already partially succeeded elsewhere; case-insensitivity surprises since Hive matches names case-insensitively.
Related errors
- Cannot rename %s to %s. View already exists
- Table already exists: %s
- View already exists: ${toIdentifier}
- Cannot create namespace %s: already exists
- Cannot rename table %s to %s: %s already exists
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/418603b19cd31132.
Report an issue: GitHub.