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

  1. Drop or rename the existing destination table first, then rerun the rename.
  2. Use a fresh destination identifier after checking catalog.tableExists(to) returns false.
  3. Make migration scripts idempotent: skip the rename if the destination already exists and matches expectations.
  4. 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

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/e210091f6b0dc67d. Report an issue: GitHub.