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

  1. 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.
  2. Serialize commits to a given view with application-level locking (e.g., per-identifier lock) if concurrent rewrites are routine.
  3. 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

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/4178b3415cd83fea. Report an issue: GitHub.