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;
});
}
}
@OverrideView on GitHub (pinned to 86d9c8fc54)
Solutions
- Deduplicate view-creation calls across threads/jobs.
- Catch AlreadyExistsException and treat as success, optionally loading the view to verify it matches expectations.
- 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
- Guard concurrent creates with an in-process lock or identifier set
- Treat AlreadyExistsException as success in idempotent create flows
- Avoid duplicate scheduled jobs creating the same view
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
- Table already exists: %s
- Table was created concurrently: %s
- Table already exists: %s
- Table already exists: %s
- Table does not exist: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/bab0251344f9cbad.
Report an issue: GitHub.