apache/iceberg · error · AlreadyExistsException

Table with same name already exists: %s

Error message

Table with same name already exists: %s

What it means

Before inserting a new view row, createView checks whether a TABLE with the same name already exists in the JDBC catalog. If it does, AlreadyExistsException is thrown, because Iceberg namespaces one object per name and a table/view name collision is unresolvable.

Source

Thrown at core/src/main/java/org/apache/iceberg/jdbc/JdbcViewOperations.java:183

    if (updatedRecords == 1) {
      LOG.debug("Successfully committed to existing view: {}", viewIdentifier);
    } else {
      throw new CommitFailedException(
          "Failed to update view %s from catalog %s", viewIdentifier, catalogName);
    }
  }

  private void createView(String newMetadataLocation) throws SQLException, InterruptedException {
    Namespace namespace = viewIdentifier.namespace();
    if (PropertyUtil.propertyAsBoolean(catalogProperties, JdbcUtil.STRICT_MODE_PROPERTY, false)
        && !JdbcUtil.namespaceExists(catalogName, connections, namespace)) {
      throw new NoSuchNamespaceException(
          "Cannot create view %s in catalog %s. Namespace %s does not exist",
          viewIdentifier, catalogName, namespace);
    }

    if (JdbcUtil.tableExists(JdbcUtil.SchemaVersion.V1, catalogName, connections, viewIdentifier)) {
      throw new AlreadyExistsException("Table with same name already exists: %s", viewIdentifier);
    }

    if (JdbcUtil.viewExists(catalogName, connections, viewIdentifier)) {
      throw new AlreadyExistsException("View already exists: %s", viewIdentifier);
    }

    int insertRecord =
        JdbcUtil.doCommitCreateView(
            connections, catalogName, namespace, viewIdentifier, newMetadataLocation);

    if (insertRecord == 1) {
      LOG.debug("Successfully committed to new view: {}", viewIdentifier);
    } else {
      throw new CommitFailedException(
          "Failed to create view %s in catalog %s", viewIdentifier, catalogName);
    }
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Choose a different name for the view, or drop the existing table first (catalog.dropTable(identifier))
  2. Check for the collision before creating: catalog.tableExists(identifier) / catalog.viewExists(identifier)
  3. Catch AlreadyExistsException to surface a friendly 'name in use' message to end users
  4. Clean up leftover tables from failed/aborted jobs in shared test environments

Example fix

// before
catalog.buildView(identify).createColumn(...).create();
// after
if (catalog.tableExists(identifier)) {
  throw new IllegalArgumentException("Name in use by table: " + identifier);
}
catalog.buildView(identifier).createColumn(...).create();
Defensive patterns

Strategy: validation

Validate before calling

if (catalog.tableExists(identifier)) {
  throw new IllegalArgumentException("Name in use by table: " + identifier);
}

Try / catch

try {
  catalog.buildView(id)...create();
} catch (AlreadyExistsException e) {
  // surface 'name in use' to the user or pick a different name
}

Prevention

When it happens

Trigger: Committing a new view (base == null) whose identifier collides with an existing table row in iceberg_tables for the same catalog and namespace.

Common situations: A name previously used for a table is reused for a view without dropping the table; cross-tool confusion where another engine created a table under the same identifier; test code reusing identifiers without cleanup.

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