apache/iceberg · error · AlreadyExistsException

Table with same name already exists: %s

Error message

Table with same name already exists: %s

What it means

An AlreadyExistsException thrown by the view Builder's replace() in RESTSessionCatalog when the target identifier currently resolves to a TABLE, not a view. Replacing a view cannot overwrite a table of the same name, so the operation is rejected before loading the view.

Source

Thrown at core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java:1777

              response.metadata(),
              endpoints);

      return new BaseView(ops, ViewUtil.fullViewName(name(), identifier));
    }

    @Override
    public View createOrReplace() {
      try {
        return replace(loadView());
      } catch (NoSuchViewException e) {
        return create();
      }
    }

    @Override
    public View replace() {
      if (tableExists(context, identifier)) {
        throw new AlreadyExistsException("Table with same name already exists: %s", identifier);
      }

      return replace(loadView());
    }

    private LoadViewResponse loadView() {
      Endpoint.check(
          endpoints,
          Endpoint.V1_LOAD_VIEW,
          () ->
              new NoSuchViewException(
                  "Unable to load view %s.%s: Server does not support endpoint %s",
                  name(), identifier, Endpoint.V1_LOAD_VIEW));

      AuthSession contextualSession = authManager.contextualSession(context, catalogAuth);
      return client
          .withAuthSession(contextualSession)
          .get(

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Check catalog.tableExists(identifier) before replace and pick a different name or drop the table first.
  2. Catch org.apache.iceberg.exceptions.AlreadyExistsException and surface the naming conflict to the user.
  3. Verify the intended object type with loadTable vs loadView to confirm what exists at that name.
  4. Use distinct naming conventions for tables vs views to avoid collisions.

Example fix

// before
catalog.buildView(ident).replace().createView(); // fails if a table named ident exists
// after
if (catalog.tableExists(ident)) { throw new IllegalStateException("name taken by table: " + ident); }
catalog.buildView(ident).replace().createView();
Defensive patterns

Strategy: validation

Validate before calling

if (catalog.tableExists(identifier)) { throw new IllegalStateException("cannot replace view: name held by table " + identifier); }

Try / catch

try { viewBuilder.replace().createView(); } catch (AlreadyExistsException e) { /* name occupied by a table */ }

Prevention

When it happens

Trigger: Calling viewBuilder(identifier).replace() when tableExists(context, identifier) is true — i.e., a table already occupies that name in the catalog.

Common situations: Name collision between tables and views in the same namespace; a migration script recreating a view where a table was created; namespace confusion after default-namespace resolution.

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