apache/iceberg · error · AlreadyExistsException

Cannot rename %s to %s. Another content of type %s with same

Error message

Cannot rename %s to %s. Another content of type %s with same name already exists

What it means

The fallback branch of validateToContentForRename: if the destination identifier holds existing content that is neither an Iceberg table nor an Iceberg view (another content type known to Nessie, e.g. other registered content kinds), the rename throws AlreadyExistsException naming the actual type. This prevents cross-type overwrites for content Nessie tracks but Iceberg does not model.

Source

Thrown at nessie/src/main/java/org/apache/iceberg/nessie/NessieIcebergClient.java:523

      // 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);
      }
    } else if (existingFromContent.getType() != type) {
      throw new RuntimeException(

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Pick a destination identifier free of any content — verify via Nessie API getEntriesFor that 'to' has no entry.
  2. Remove the foreign content at the destination key through the tool that owns it, then rerun the rename.
  3. Upgrade the Iceberg-Nessie integration so newer content types are mapped/handled instead of hitting the fallback.
  4. Separate Iceberg content into its own Nessie namespace/repo to avoid cross-type key collisions.

Example fix

// before
catalog.renameTable(t, TableIdentifier.of("ns","shared")); // 'ns.shared' holds foreign content
// after
Content dest = nessieApi.getContent().refName("main").key(ContentKey.of("ns","shared")).get()
    .get(ContentKey.of("ns","shared"));
if (dest == null) {
  catalog.renameTable(t, TableIdentifier.of("ns","shared"));
}
Defensive patterns

Strategy: validation

Validate before calling

// via Nessie API: ensure destination key holds no content of any kind
Map<ContentKey, Content> m = nessieApi.getContent()
    .refName(refName).key(ContentKey.of(to.namespace().levels())).get();
boolean destFree = !m.containsKey(ContentKey.of(to.namespace().levels()));

Try / catch

try {
  catalog.renameTable(from, to);
} catch (AlreadyExistsException e) {
  if (String.valueOf(e.getMessage()).contains("Another content of type")) {
    // foreign content at destination; route to the owning tool or choose another name
    handleForeignContentCollision(to, e);
  } else throw e;
}

Prevention

When it happens

Trigger: renameTable/renameView where fetchContent(to) returns non-null IcebergContent whose getType() is neither ICEBERG_TABLE nor ICEBERG_VIEW — the destination key holds other Nessie-managed content.

Common situations: Nessie namespaces host non-Iceberg content (other engines/models registered at the same content key); a mixed-workload Nessie repository where identifiers collide across content kinds; upgraded/patched content model introducing types the Iceberg client version doesn't recognize.

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