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

InMemoryCatalog.renameTable throws AlreadyExistsException when a table already exists at the destination identifier. Renaming is not a merge; the catalog refuses to overwrite an existing table at 'to'.

Source

Thrown at core/src/main/java/org/apache/iceberg/inmemory/InMemoryCatalog.java:182

  @Override
  public void renameTable(TableIdentifier from, TableIdentifier to) {
    if (from.equals(to)) {
      return;
    }

    synchronized (this) {
      if (!namespaceExists(to.namespace())) {
        throw new NoSuchNamespaceException(
            "Cannot rename %s to %s. Namespace does not exist: %s", from, to, to.namespace());
      }

      String fromLocation = tables.get(from);
      if (null == fromLocation) {
        throw new NoSuchTableException("Cannot rename %s to %s. Table does not exist", from, to);
      }

      if (tables.containsKey(to)) {
        throw new AlreadyExistsException("Cannot rename %s to %s. Table already exists", from, to);
      }

      if (views.containsKey(to)) {
        throw new AlreadyExistsException("Cannot rename %s to %s. View already exists", from, to);
      }

      tables.put(to, fromLocation);
      tables.remove(from);
    }
  }

  @Override
  public void createNamespace(Namespace namespace) {
    createNamespace(namespace, Collections.emptyMap());
  }

  @Override
  public void createNamespace(Namespace namespace, Map<String, String> metadata) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Drop or rename the existing destination table first
  2. Choose a unique destination identifier (e.g. append timestamp)
  3. Check catalog.tableExists(to) before renaming and handle collisions
  4. Catch AlreadyExistsException to skip if the destination already has the data

Example fix

// before
catalog.renameTable(from, to);
// after
if (!catalog.tableExists(to)) {
  catalog.renameTable(from, to);
} else {
  catalog.dropTable(to);
  catalog.renameTable(from, to);
}
Defensive patterns

Strategy: validation

Validate before calling

if (catalog.tableExists(to)) { catalog.dropTable(to); }
catalog.renameTable(from, to);

Try / catch

try { catalog.renameTable(from, to); } catch (AlreadyExistsException e) { /* resolve collision: drop or pick new name */ }

Prevention

When it happens

Trigger: Calling catalog.renameTable(from, to) where tables already contains 'to'. E.g. renaming 'events' to 'events_backup' when 'events_backup' already exists from a previous rename.

Common situations: Cron jobs producing colliding backup names; retrying a partially completed rename workflow; test fixtures reusing names.

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