apache/iceberg · warning · CommitFailedException

Failed to update view %s from catalog %s

Error message

Failed to update view %s from catalog %s

What it means

updateView performs a conditional UPDATE of the view row (WHERE metadata_location = oldMetadataLocation) and expects exactly 1 updated row. If 0 (or more than 1) rows are updated, a CommitFailedException is thrown, meaning the expected prior state was not found or the update did not match exactly one view.

Source

Thrown at core/src/main/java/org/apache/iceberg/jdbc/JdbcViewOperations.java:168

    String baseMetadataLocation = base != null ? base.metadataFileLocation() : null;

    if (!Objects.equals(baseMetadataLocation, catalogMetadataLocation)) {
      throw new CommitFailedException(
          "Cannot commit %s: metadata location %s has changed from %s",
          viewIdentifier, baseMetadataLocation, catalogMetadataLocation);
    }
  }

  private void updateView(String newMetadataLocation, String oldMetadataLocation)
      throws SQLException, InterruptedException {
    int updatedRecords =
        JdbcUtil.updateView(
            connections, catalogName, viewIdentifier, newMetadataLocation, oldMetadataLocation);

    if (updatedRecords == 1) {
      LOG.debug("Successfully committed to existing view: {}", viewIdentifier);
    } else {
      throw new CommitFailedException(
          "Failed to update view %s from catalog %s", viewIdentifier, catalogName);
    }
  }

  private void createView(String newMetadataLocation) throws SQLException, InterruptedException {
    Namespace namespace = viewIdentifier.namespace();
    if (PropertyUtil.propertyAsBoolean(catalogProperties, JdbcUtil.STRICT_MODE_PROPERTY, false)
        && !JdbcUtil.namespaceExists(catalogName, connections, namespace)) {
      throw new NoSuchNamespaceException(
          "Cannot create view %s in catalog %s. Namespace %s does not exist",
          viewIdentifier, catalogName, namespace);
    }

    if (JdbcUtil.tableExists(JdbcUtil.SchemaVersion.V1, catalogName, connections, viewIdentifier)) {
      throw new AlreadyExistsException("Table with same name already exists: %s", viewIdentifier);
    }

    if (JdbcUtil.viewExists(catalogName, connections, viewIdentifier)) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Refresh the view (viewOps.refresh()) to pick up the new metadata location and retry the commit
  2. Catch CommitFailedException and retry with backoff — this error is designed to be retried after re-reading state
  3. Check for duplicate rows in iceberg_views for the same catalog/namespace/view name and clean them up
  4. Verify the view was not dropped/recreated concurrently by another process
  5. Serialize writers per view or use an external lock if concurrent commits are routine

Example fix

// before: unconditional retry on same stale object
ops.commit(metadata, base); // fails repeatedly
// after: refresh between attempts
try {
  ops.commit(metadata, base);
} catch (CommitFailedException e) {
  ops.refresh();
  ops.commit(rebase(metadata), ops.current());
}
Defensive patterns

Strategy: retry

Validate before calling

// verify exactly one row exists for this view before updating
SELECT COUNT(*) FROM iceberg_views
WHERE catalog_name = ? AND view_namespace = ? AND view_name = ?; // expect 1

Try / catch

try {
  viewOps.commit(request);
} catch (CommitFailedException e) {
  viewOps.refresh();
  if (viewOps.current() != null) retryAsUpdate(); else retryAsCreate();
}

Prevention

When it happens

Trigger: Concurrent commit changed the metadata location between validateMetadataLocation and the UPDATE; the view row was deleted concurrently; the view row exists under a different catalog_name, so the conditional UPDATE matches nothing.

Common situations: Race between two writers committing the same view nearly simultaneously; view dropped by another process mid-commit; duplicated catalog rows from a manually seeded or corrupted catalog table.

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/442bd8a33da71970. Report an issue: GitHub.