apache/iceberg · error · AlreadyExistsException

View already exists: %s

Error message

View already exists: %s

What it means

BaseViewBuilder.create commits a new view but first checks ViewOperations.current(). If view metadata already exists, it throws AlreadyExistsException because create() must not overwrite an existing view (use createOrReplace or replace for that).

Source

Thrown at core/src/main/java/org/apache/iceberg/view/BaseMetastoreViewCatalog.java:184

    @Override
    public View replace() {
      return replace(newViewOps(identifier));
    }

    @Override
    public View createOrReplace() {
      ViewOperations ops = newViewOps(identifier);
      if (null == ops.current()) {
        return create(ops);
      } else {
        return replace(ops);
      }
    }

    private View create(ViewOperations ops) {
      if (null != ops.current()) {
        throw new AlreadyExistsException("View already exists: %s", identifier);
      }

      Preconditions.checkState(
          !representations.isEmpty(), "Cannot create view without specifying a query");
      Preconditions.checkState(null != schema, "Cannot create view without specifying schema");
      Preconditions.checkState(
          null != defaultNamespace, "Cannot create view without specifying a default namespace");

      ViewVersion viewVersion =
          ImmutableViewVersion.builder()
              .versionId(1)
              .schemaId(schema.schemaId())
              .addAllRepresentations(representations)
              .defaultNamespace(defaultNamespace)
              .defaultCatalog(defaultCatalog)
              .timestampMillis(System.currentTimeMillis())
              .putAllSummary(EnvironmentContext.get())
              .build();

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Use createOrReplace(...) instead of create(...) when overwriting is intended
  2. Drop the existing view first (catalog.dropView(identifier))
  3. Use catalog.viewExists(identifier) as an existence guard before create

Example fix

// before
catalog.buildView(ident).withQuery("sql", "select 1").create();
// after
catalog.buildView(ident).withQuery("sql", "select 1").createOrReplace();
Defensive patterns

Strategy: try-catch

Validate before calling

if (catalog.viewExists(identifier) && !allowOverwrite) { throw new IllegalStateException("View " + identifier + " already exists"); }

Try / catch

try { return builder.create(); } catch (AlreadyExistsException e) { return catalog.loadView(identifier); /* idempotent create */ }

Prevention

When it happens

Trigger: Calling catalog.buildView(ident)...create() (or createOrReplace where the replace branch routes here) when a view with that identifier already exists in the metastore.

Common situations: Race between two jobs creating the same view name; rerunning idempotent setup scripts without createOrReplace; leftover view from a previous run.

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