apache/iceberg · error · AlreadyExistsException
View was created concurrently: %s
Error message
View was created concurrently: %s
What it means
When creating a view, the builder commits from a null base metadata. If the metastore's optimistic concurrency check raises CommitFailedException (another process created the view in the meantime), the library converts it to AlreadyExistsException('View was created concurrently') since the null-base commit only succeeds for a fresh view.
Source
Thrown at core/src/main/java/org/apache/iceberg/view/BaseMetastoreViewCatalog.java:216
.defaultNamespace(defaultNamespace)
.defaultCatalog(defaultCatalog)
.timestampMillis(System.currentTimeMillis())
.putAllSummary(EnvironmentContext.get())
.build();
properties.putAll(viewOverrideProperties());
ViewMetadata viewMetadata =
ViewMetadata.builder()
.setProperties(properties)
.setLocation(null != location ? location : defaultWarehouseLocation(identifier))
.setCurrentVersion(viewVersion, schema)
.build();
try {
ops.commit(null, viewMetadata);
} catch (CommitFailedException ignored) {
throw new AlreadyExistsException("View was created concurrently: %s", identifier);
}
return new BaseView(ops, ViewUtil.fullViewName(name(), identifier));
}
private View replace(ViewOperations ops) {
if (tableExists(identifier)) {
throw new AlreadyExistsException("Table with same name already exists: %s", identifier);
}
if (null == ops.current()) {
throw new NoSuchViewException("View does not exist: %s", identifier);
}
Preconditions.checkState(
!representations.isEmpty(), "Cannot replace view without specifying a query");
Preconditions.checkState(null != schema, "Cannot replace view without specifying schema");
Preconditions.checkState(View on GitHub (pinned to 86d9c8fc54)
Solutions
- Catch AlreadyExistsException and treat the existing view as the outcome (idempotent create)
- Retry loadView/createOrReplace after the conflict
- Use external locking or a single provisioning job to avoid concurrent DDL
Example fix
// before
view = catalog.buildView(ident).withQuery("sql", q).create();
// after
try {
view = catalog.buildView(ident).withQuery("sql", q).create();
} catch (AlreadyExistsException e) {
view = catalog.loadView(ident); // created concurrently
} Defensive patterns
Strategy: retry
Try / catch
try { return builder.create(); } catch (AlreadyExistsException e) { return catalog.loadView(identifier); /* concurrent creation won */ } Prevention
- Make view creation idempotent: treat AlreadyExistsException as success and load the view
- Run DDL provisioning from a single scheduler instance
- Use retry with small backoff for concurrent DDL
When it happens
Trigger: Two concurrent create() calls (or create racing another writer) for the same view identifier; the loser's ops.commit(null, metadata) fails with CommitFailedException.
Common situations: Multiple schedulers/workers running the same DDL job simultaneously; CI pipelines racing to provision views.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot commit to view %s metadata location from %s to %s bec
- Table already exists: %s
- Namespace %s is not empty. Contains %d view(s).
- Cannot list views for namespace. Namespace does not exist: %
- Cannot rename %s to %s. View does not exist
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/1842e9daa3217d8f.
Report an issue: GitHub.