{"record":{"id":"183d856d0baad30f","repo":"apache/iceberg","slug":"cannot-commit-stale-view-metadata","errorCode":null,"errorMessage":"Cannot commit: stale view metadata","messagePattern":"Cannot commit: stale view metadata","errorType":"exception","errorClass":"CommitFailedException","httpStatus":409,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/view/BaseViewOperations.java","lineNumber":111,"sourceCode":"        shouldRefresh = true;\n      }\n\n      currentMetadata = null;\n      currentMetadataLocation = null;\n      version = -1;\n      throw e;\n    }\n\n    return current();\n  }\n\n  @Override\n  @SuppressWarnings(\"ImmutablesReferenceEquality\")\n  public void commit(ViewMetadata base, ViewMetadata metadata) {\n    // if the metadata is already out of date, reject it\n    if (base != current()) {\n      if (base != null) {\n        throw new CommitFailedException(\"Cannot commit: stale view metadata\");\n      } else {\n        // when current is non-null, the view exists. but when base is null, the commit is trying\n        // to create the view\n        throw new AlreadyExistsException(\"View already exists: %s\", viewName());\n      }\n    }\n\n    // if the metadata is not changed, return early\n    if (base == metadata) {\n      LOG.info(\"Nothing to commit.\");\n      return;\n    }\n\n    long start = System.currentTimeMillis();\n    doCommit(base, metadata);\n    requestRefresh();\n\n    LOG.info(","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/view/BaseViewOperations.java#L93-L129","documentation":"BaseViewOperations.commit compares the commit's base metadata against the current in-memory/current metadata by reference. When base is non-null but differs from current, the view was modified by someone else and this commit's optimistic concurrency check fails with a CommitFailedException so the caller can retry.","triggerScenarios":"A view operation built on stale metadata commits while another client has already updated the view; the internal metadata cache was refreshed between read and commit.","commonSituations":"Long-running view update transactions racing with external updates; two Spark sessions altering the same view; automation pipelines updating view SQL concurrently.","solutions":["Refresh the view (reload metadata) and retry the commit","Wrap the update in a retry loop that re-reads the view on CommitFailedException","Serialize view updates through a single writer or lock","Shorten the window between reading and committing view metadata"],"exampleFix":"// before\nops.commit(staleBase, newMetadata);\n// after\nTasks.foreach(newMetadata)\n    .retry(3)\n    .exponentialBackoff(100, 10000)\n    .suppressExceptions()\n    .run(m -> {\n      ViewMetadata base = ((BaseViewOperations) ops).current();\n      ops.commit(base, m);\n    });","handlingStrategy":"retry","validationCode":"ViewMetadata current = ((BaseViewOperations) ops).current(); boolean stale = (base != current);","typeGuard":null,"tryCatchPattern":"Tasks.foreach(metadata).retry(3).exponentialBackoff(100, 10000).run(m -> ops.commit(((BaseViewOperations) ops).current(), m));","preventionTips":["Always re-read current metadata immediately before commit","Use Tasks.foreach retry loops for optimistic-concurrency commits","Avoid holding view metadata for long periods before committing"],"tags":["concurrency","commit-failed","stale-metadata","retryable"],"backgroundTag":"invalid-state-transition","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}