apache/iceberg · error · AlreadyExistsException

View already exists: %s

Error message

View already exists: %s

What it means

Inside the views.compute lambda of the view commit path, if the expected location does not match and base is null (a create), a view under this name was created concurrently. InMemoryCatalog throws AlreadyExistsException instead of overwriting the winner, keeping create operations idempotent-safe under races.

Source

Thrown at core/src/main/java/org/apache/iceberg/inmemory/InMemoryCatalog.java:517

      String oldLocation = base == null ? null : currentMetadataLocation();

      synchronized (InMemoryCatalog.this) {
        if (null == base && !namespaceExists(identifier.namespace())) {
          throw new NoSuchNamespaceException(
              "Cannot create view %s. Namespace does not exist: %s",
              identifier, identifier.namespace());
        }

        if (tables.containsKey(identifier)) {
          throw new AlreadyExistsException("Table with same name already exists: %s", identifier);
        }

        views.compute(
            identifier,
            (k, existingLocation) -> {
              if (!Objects.equal(existingLocation, oldLocation)) {
                if (null == base) {
                  throw new AlreadyExistsException("View already exists: %s", identifier);
                }

                if (null == existingLocation) {
                  throw new NoSuchViewException("View does not exist: %s", identifier);
                }

                throw new CommitFailedException(
                    "Cannot commit to view %s metadata location from %s to %s "
                        + "because it has been concurrently modified to %s",
                    identifier, oldLocation, newLocation, existingLocation);
              }

              return newLocation;
            });
      }
    }

    @Override

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Deduplicate view-creation calls across threads/jobs.
  2. Catch AlreadyExistsException and treat as success, optionally loading the view to verify it matches expectations.
  3. Use a check-then-create guarded by external locking if creation must be exclusive.

Example fix

// before
catalog.buildView(ident).withQuery("spark", q).create();

// after
try {
  catalog.buildView(ident).withQuery("spark", q).create();
} catch (AlreadyExistsException e) {
  catalog.loadView(ident); // concurrent create won
}
Defensive patterns

Strategy: try-catch

Try / catch

try { viewBuilder.create(); } catch (AlreadyExistsException e) { View existing = catalog.loadView(ident); // verify or adopt concurrent creation }

Prevention

When it happens

Trigger: Two concurrent createView/buildView(...).create() calls for the same identifier: one inserts first; the other finds existingLocation != null while its base == null.

Common situations: Parallel test fixtures creating the same view; duplicate scheduled jobs; idempotent retry of a create that actually succeeded the first time.

Related errors


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