apache/iceberg · error · AlreadyExistsException

Cannot rename %s to %s. View already exists

Error message

Cannot rename %s to %s. View already exists

What it means

renameTableOrView() throws AlreadyExistsException when a view already exists at the rename destination identifier. Since Iceberg tables and views share the Hive Metastore namespace (distinguished by table type), a view at the destination also blocks a rename.

Source

Thrown at hive-metastore/src/main/java/org/apache/iceberg/hive/HiveCatalog.java:410

  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(
          client -> {
            MetastoreUtil.alterTable(client, fromDatabase, fromName, table);
            return null;
          });

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Check catalog.viewExists(to) before renaming and choose a different destination name.
  2. Drop the conflicting view first if it is no longer needed.
  3. In scripts, check both tableExists and viewExists for the destination.
  4. Use unique destination names to avoid races with concurrent view creation.

Example fix

// before
catalog.renameView(from, TableIdentifier.of(db, "summary"));
// after
TableIdentifier to = TableIdentifier.of(db, "summary");
if (catalog.viewExists(to) || catalog.tableExists(to)) {
  throw new IllegalStateException("Destination name in use: " + to);
}
catalog.renameView(from, to);
Defensive patterns

Strategy: validation

Validate before calling

TableIdentifier to = TableIdentifier.of(db, "summary");
if (catalog.viewExists(to) || catalog.tableExists(to)) {
  throw new IllegalStateException("Destination name in use: " + to);
}
catalog.renameView(from, to);

Try / catch

try {
  catalog.renameView(from, to);
} catch (AlreadyExistsException e) {
  // resolve view/table name collision, then retry
  throw e;
}

Prevention

When it happens

Trigger: Calling catalog.renameTable(from, to) or catalog.renameView(from, to) where to passes the tableExists check but a Hive view (ICEBERG_VIEW type) named to.name() exists in to.namespace().

Common situations: A view with the intended table name exists (views and tables share the HMS name space); leftover views from earlier experiments; concurrent creation of a view at the destination; case-insensitive name collisions.

Related errors


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