apache/iceberg · warning · CommitFailedException
Cannot commit to view %s metadata location from %s to %s bec
Error message
Cannot commit to view %s metadata location from %s to %s because it has been concurrently modified to %s
What it means
InMemoryCatalog throws this CommitFailedException when a view commit's expected metadata location no longer matches the location currently stored. Another writer modified the view between the read of the old location and the optimistic commit, so the compare-and-swap precondition fails and the commit is rejected for retry.
Source
Thrown at core/src/main/java/org/apache/iceberg/inmemory/InMemoryCatalog.java:524
}
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
public FileIO io() {
return io;
}
@Override
protected String viewName() {
return fullViewName;View on GitHub (pinned to 86d9c8fc54)
Solutions
- Retry the operation: re-read the view (loadView/loadTable) to get the fresh state, reapply the change, and commit again — CommitFailedException is designed to be retried.
- Serialize commits to a given view with application-level locking (e.g., per-identifier lock) if concurrent rewrites are routine.
- Check for accidental duplicate jobs or test parallelism writing the same view simultaneously and stagger them.
Example fix
// before
view.updateSchema().setRequired(1).commit(); // may throw CommitFailedException once
// after
RetryUtil.retry(CommitFailedException.class, 3, () -> {
View view = catalog.loadView(identifier);
view.updateSchema().setRequired(1).commit();
return null;
}); Defensive patterns
Strategy: retry
Validate before calling
View current = catalog.loadView(identifier); // compare metadata locations before committing
if (!current.location().equals(expectedLocation)) { /* refresh and reapply */ } Try / catch
try {
viewOp.commit();
} catch (CommitFailedException e) {
View fresh = catalog.loadView(identifier);
// reapply change on fresh state and retry
} Prevention
- Always wrap view commits in a retry loop for CommitFailedException.
- Keep read-to-commit windows short to reduce concurrent-modification chances.
- Use per-identifier locking when multiple clients routinely rewrite the same view.
When it happens
Trigger: Two threads or processes call InMemoryCatalog operations like replaceView/updateView on the same view identifier concurrently; the second commit's oldLocation does not equal the view's current stored metadata location.
Common situations: Concurrent Spark/Flink jobs or test threads rewriting the same view; a long-running planning phase followed by commit while another client committed first; optimistic-concurrency races in tests that reuse one in-memory catalog across threads.
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 table %s metadata location from %s to %s be
- View was created concurrently: %s
- View was updated concurrently: %s
- Failed to commit
- Table already exists: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/4178b3415cd83fea.
Report an issue: GitHub.