{"record":{"id":"7bd3e373da600849","repo":"apache/iceberg","slug":"commit-status-check-commit-to-of-unknown-n","errorCode":null,"errorMessage":"Commit status check: Commit to {} of {} unknown, new metadata location is not current or in history","messagePattern":"Commit status check: Commit to (.+?) of (.+?) unknown, new metadata location is not current or in history","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/src/main/java/org/apache/iceberg/BaseMetastoreOperations.java","lineNumber":72,"sourceCode":"   * CommitStatus#UNKNOWN}, because possible pending retries might still commit the change.\n   *\n   * @param tableOrViewName full name of the Table/View\n   * @param newMetadataLocation the path of the new commit file\n   * @param properties properties for retry\n   * @param commitStatusSupplier check if the latest metadata presents or not using metadata\n   *     location for table.\n   * @return Commit Status of Success or Unknown\n   */\n  protected CommitStatus checkCommitStatus(\n      String tableOrViewName,\n      String newMetadataLocation,\n      Map<String, String> properties,\n      Supplier<Boolean> commitStatusSupplier) {\n    CommitStatus strictStatus =\n        checkCommitStatusStrict(\n            tableOrViewName, newMetadataLocation, properties, commitStatusSupplier);\n    if (strictStatus == CommitStatus.FAILURE) {\n      LOG.warn(\n          \"Commit status check: Commit to {} of {} unknown, new metadata location is not current \"\n              + \"or in history\",\n          tableOrViewName,\n          newMetadataLocation);\n      return CommitStatus.UNKNOWN;\n    }\n    return strictStatus;\n  }\n\n  /**\n   * Attempt to load the content and see if any current or past metadata location matches the one we\n   * were attempting to set. This is used as a last resort when we are dealing with exceptions that\n   * may indicate the commit has failed and don't have proof that this is the case, but we can be\n   * sure that no retry attempts for the commit will be successful later. Note that all the previous\n   * locations must also be searched on the chance that a second committer was able to successfully\n   * commit on top of our commit. When the {@code newMetadataLocation} is not in the history the\n   * method returns {@link CommitStatus#FAILURE}, when the {@code commitStatusSupplier} fails\n   * repeatedly the method returns {@link CommitStatus#UNKNOWN}.","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/BaseMetastoreOperations.java#L54-L90","documentation":"This is a WARN log, not a thrown exception: after a commit whose outcome is unclear (e.g. an HTTP timeout), Iceberg re-checks the metastore to determine whether the commit actually succeeded. When the new metadata location is neither the table's current location nor in its history, the commit is definitively a failure, but since the original error was ambiguous, the method conservatively returns CommitStatus.UNKNOWN instead of FAILURE. Callers treat UNKNOWN as unrecoverable and propagate a CommitFailedException-style uncertainty to the user.","triggerScenarios":"checkCommitStatus is invoked after a commit exception; checkCommitStatusStrict determined FAILURE because the metadata location in the metastore is different and newMetadataLocation is absent from the version history stored in the 'previous-versions'/'metadata-log' properties.","commonSituations":"Concurrent writers where another client committed a different snapshot before this commit; Hive/Glue/Nessie metastores where commit racing is common; network timeouts during commit causing retry logic to run the status check.","solutions":["Re-run the commit operation; UNKNOWN status means the table was not modified by this commit so a fresh commit is safe.","Check the table's current metadata location in the metastore to identify which concurrent writer won.","Reduce commit concurrency or use a catalog with proper atomic commit semantics (e.g. REST catalog with conditional writes) instead of racing clients.","Enable debug logging on the operations class to compare the expected vs actual metadata location."],"exampleFix":"// before: retrying inside the same failed commit context\ntry { table.updateSchema()...commit(); } catch (CommitFailedException e) { /* uncertain */ }\n// after: reload and re-apply on UNKNOWN status\nTable reloaded = catalog.loadTable(identifier);\nreloaded.updateSchema().addColumn(\"new_col\", Types.LongType.get()).commit();","handlingStrategy":"retry","validationCode":"// before committing, check current metadata location matches your last-read state\nTableMetadata current = ((HasTableOperations) table).operations().current();\nboolean stillCurrent = current.metadataFileLocation().equals(lastSeenMetadataLocation);","typeGuard":null,"tryCatchPattern":"try { table.refresh(); /* reapply changes */ table.updateSpec()...commit(); } catch (CommitFailedException e) { // reload table and reapply from scratch }","preventionTips":["Always reload the table and reapply changes after any uncertain commit outcome","Minimize concurrent writers to the same table","Use catalogs with strong atomic commit guarantees","Log metadata locations to trace which writer won a race"],"tags":["commit-status","concurrency","metastore"],"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-14T11:17:12.474Z"}