apache/iceberg · error · AlreadyExistsException
View already exists: %s
Error message
View already exists: %s
What it means
AlreadyExistsException raised by JdbcViewOperations.doCommit when creating a NEW view (no current metadata location) hits a constraint violation in the catalog table — meaning a row for this view identifier already exists in iceberg_views. This is the create-vs-concurrent-create race detection: the INSERT's unique-key guard fired.
Source
Thrown at core/src/main/java/org/apache/iceberg/jdbc/JdbcViewOperations.java:125
updateView(newMetadataLocation, oldMetadataLocation);
} else {
// view does not exist, create it
LOG.debug("Committing new view: {}", viewName());
createView(newMetadataLocation);
}
} catch (SQLTimeoutException e) {
throw new UncheckedSQLException(e, "Database Connection timeout");
} catch (SQLTransientConnectionException | SQLNonTransientConnectionException e) {
throw new UncheckedSQLException(e, "Database Connection failed");
} catch (DataTruncation e) {
throw new UncheckedSQLException(e, "Database data truncation error");
} catch (SQLWarning e) {
throw new UncheckedSQLException(e, "Database warning");
} catch (SQLException e) {
if (JdbcUtil.isConstraintViolation(e)) {
if (currentMetadataLocation() == null) {
throw new AlreadyExistsException(e, "View already exists: %s", viewIdentifier);
} else {
throw new UncheckedSQLException(e, "View already exists: %s", viewIdentifier);
}
}
throw new UncheckedSQLException(e, "Unknown failure");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new UncheckedInterruptedException(e, "Interrupted during commit");
}
}
@Override
protected String viewName() {
return viewIdentifier.toString();
}
@OverrideView on GitHub (pinned to 86d9c8fc54)
Solutions
- Check catalog.viewExists before creating, or handle AlreadyExistsException and reuse the existing view
- Use CREATE OR REPLACE semantics where appropriate for your workflow
- If the row is stale/corrupt (view was dropped but row remains), clean up the catalog row
- Serialize view creation for the same identifier in your orchestration
Example fix
// before
catalog.createView(ident, schema, spec, sql); // AlreadyExistsException on race
// after
if (!catalog.viewExists(ident)) {
catalog.createView(ident, schema, spec, sql);
} else {
View existing = catalog.loadView(ident); // reuse
} Defensive patterns
Strategy: try-catch
Validate before calling
boolean exists = catalog.viewExists(ident);
if (exists) {
throw new IllegalStateException("View already exists: " + ident);
} Try / catch
try {
catalog.createView(ident, schema, spec, sql);
} catch (AlreadyExistsException e) {
// concurrent create won; load the existing view instead
View existing = catalog.loadView(ident);
} Prevention
- Check viewExists before create and handle AlreadyExistsException gracefully
- Serialize creation of same-named views in orchestration
- Don't manually insert rows into iceberg_views
When it happens
Trigger: CREATE VIEW on a name that already exists, or two sessions concurrently creating the same view — one insert succeeds, the other trips the primary-key/unique constraint and gets this exception.
Common situations: Race between two jobs both issuing CREATE VIEW IF NOT EXISTS-style logic, or a stale catalog client that didn't see the existing row during the pre-insert existence check.
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
- View does not exist: %s
- View already exists: %s
- View with same name already exists: %s.%s
- %s already exists: %s.%s
- View already exists: %s.%s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/4d26965a619c4ab7.
Report an issue: GitHub.