apache/iceberg · warning · CommitFailedException
Cannot commit to table %s metadata location from %s to %s be
Error message
Cannot commit to table %s metadata location from %s to %s because it has been concurrently modified to %s
What it means
This is the optimistic-concurrency conflict of the in-memory catalog: the commit expected the table's metadata location to equal oldLocation, but the map holds a different existingLocation, meaning another committer advanced the table in between. Per Iceberg's commit contract, CommitFailedException signals the caller to refresh and retry the update against the new state.
Source
Thrown at core/src/main/java/org/apache/iceberg/inmemory/InMemoryCatalog.java:454
if (views.containsKey(tableIdentifier)) {
throw new AlreadyExistsException(
"View with same name already exists: %s", tableIdentifier);
}
tables.compute(
tableIdentifier,
(k, existingLocation) -> {
if (!Objects.equal(existingLocation, oldLocation)) {
if (null == base) {
throw new AlreadyExistsException("Table already exists: %s", tableName());
}
if (null == existingLocation) {
throw new NoSuchTableException("Table does not exist: %s", tableName());
}
throw new CommitFailedException(
"Cannot commit to table %s metadata location from %s to %s "
+ "because it has been concurrently modified to %s",
tableIdentifier, oldLocation, newLocation, existingLocation);
}
return newLocation;
});
}
}
@Override
public FileIO io() {
return fileIO;
}
@Override
protected String tableName() {
return fullTableName;
}View on GitHub (pinned to 86d9c8fc54)
Solutions
- Retry the commit: catch CommitFailedException, call table.refresh(), re-apply the update, and commit again (Iceberg's RetryUtil/Tasks.foreach with retry works well).
- Reduce conflict windows by shortening transaction scopes or partitioning work across distinct tables.
- Ensure every retry reloads/refreshes metadata; never reuse stale TableMetadata.
Example fix
// before
table.updateSchema().addColumn("c", Types.IntegerType.get()).commit();
// after
Tasks.foreach(table)
.retry(3)
.onlyOn(CommitFailedException.class)
.run(t -> t.refresh());
table.refresh();
table.updateSchema().addColumn("c", Types.IntegerType.get()).commit(); Defensive patterns
Strategy: retry
Try / catch
try { table.commit(update); } catch (CommitFailedException e) { table.refresh(); /* re-apply update on refreshed metadata and retry, bounded attempts */ } Prevention
- Always refresh() the table before reapplying a failed commit
- Use Tasks.foreach(...).retry(n).onlyOn(CommitFailedException.class) for commits
- Keep transactions short to shrink conflict windows
- Partition concurrent writers across distinct tables/partitions
When it happens
Trigger: Two writers load the same table and both call commit(); the loser sees existingLocation != oldLocation and neither base nor existingLocation is null. Any concurrent metadata operation (schema update, append, partition spec change) on the same table.
Common situations: Multiple executors/threads appending to one table; concurrent schema evolution and writes; retry loops that do not refresh the table before recommitting.
Related errors
- Cannot commit to view %s metadata location from %s to %s bec
- View was updated concurrently: %s
- Cannot commit %s: concurrent update detected
- Failed to commit
- Cannot commit file that conflicts with existing partition: %
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/bc274ee4daac14bd.
Report an issue: GitHub.