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
Same guard as the view case: validateToContentForRename throws AlreadyExistsException when the rename destination already contains content of type ICEBERG_TABLE. The rename is rejected so an existing table is never clobbered by a Put of other content.
Source
Thrown at nessie/src/main/java/org/apache/iceberg/nessie/NessieIcebergClient.java:521
// to catch all kinds of network errors (e.g. connection reset). Network code implementation
// details and all kinds of network devices can induce unexpected behavior. So better be
// safe than sorry.
throw new CommitStateUnknownException(ex);
}
// Intentionally just "throw through" Nessie's HttpClientException here and do not "special
// case"
// just the "timeout" variant to propagate all kinds of network errors (e.g. connection reset).
// Network code implementation details and all kinds of network devices can induce unexpected
// behavior. So better be safe than sorry.
}
private static void validateToContentForRename(
TableIdentifier from, TableIdentifier to, IcebergContent existingToContent) {
if (existingToContent != null) {
if (existingToContent.getType() == Content.Type.ICEBERG_VIEW) {
throw new AlreadyExistsException("Cannot rename %s to %s. View already exists", from, to);
} else if (existingToContent.getType() == Content.Type.ICEBERG_TABLE) {
throw new AlreadyExistsException("Cannot rename %s to %s. Table already exists", from, to);
} else {
throw new AlreadyExistsException(
"Cannot rename %s to %s. Another content of type %s with same name already exists",
from, to, existingToContent.getType());
}
}
}
private static void validateFromContentForRename(
TableIdentifier from, Content.Type type, IcebergContent existingFromContent) {
if (existingFromContent == null) {
if (type == Content.Type.ICEBERG_VIEW) {
throw new NoSuchViewException("View does not exist: %s", from);
} else if (type == Content.Type.ICEBERG_TABLE) {
throw new NoSuchTableException("Table does not exist: %s", from);
} else {
throw new RuntimeException("Cannot perform rename for content type: " + type);
}View on GitHub (pinned to 86d9c8fc54)
Solutions
- Drop or rename the existing destination table first, then rerun the rename.
- Use a fresh destination identifier after checking catalog.tableExists(to) returns false.
- Make migration scripts idempotent: skip the rename if the destination already exists and matches expectations.
- If an unintended duplicate exists, inspect Nessie content listing for the namespace to clean up the collision.
Example fix
// before
catalog.renameView(v1, TableIdentifier.of("ns","report")); // table 'ns.report' exists
// after
TableIdentifier dest = TableIdentifier.of("ns","report");
if (!catalog.tableExists(dest)) {
catalog.renameView(v1, dest);
} Defensive patterns
Strategy: validation
Validate before calling
if (catalog.tableExists(to) || catalog.namespaceExists(...)) { /* pick new name */ }
// minimal check:
boolean destFree = !catalog.tableExists(to);
if (!destFree) { throw new ValidationException("table exists at destination: " + to); } Try / catch
try {
catalog.renameView(from, to);
} catch (AlreadyExistsException e) {
// destination is an existing table; choose a free identifier
to = nextAvailableIdentifier(to);
catalog.renameView(from, to);
} Prevention
- Guard renames with catalog.tableExists(destination).
- Generate destinations from a fresh listing of the namespace, not hardcoded names.
- Re-run idempotent migrations safely by checking destination state first.
- Document naming conventions so table/view identifiers never overlap.
When it happens
Trigger: catalog.renameTable(from, to) where 'to' is an existing table, or catalog.renameView(from, to) where 'to' names an existing table — fetchContent(to) returns non-null content typed ICEBERG_TABLE.
Common situations: Copy/paste of rename scripts with stale destination names; re-running a migration that already created the destination table; schema-drift tools recreating a table at the target name between planning and execution.
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 rename %s to %s. View already exists
- Cannot rename %s to %s. Another content of type %s with same
- Table does not exist: %s
- Cannot rename table %s to %s: %s already exists
- Table %s already exists in the database %s and catalog %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/e210091f6b0dc67d.
Report an issue: GitHub.