{"record":{"id":"cd479e2216ac226c","repo":"apache/iceberg","slug":"cannot-commit-base-metadata-location-s-is-not","errorCode":null,"errorMessage":"Cannot commit: Base metadata location '%s' is not same as the current table metadata location '%s' for %s.%s","messagePattern":"Cannot commit: Base metadata location '(.+?)' is not same as the current table metadata location '(.+?)' for (.+?)\\.(.+?)","errorType":"exception","errorClass":"CommitFailedException","httpStatus":null,"severity":"error","filePath":"hive-metastore/src/main/java/org/apache/iceberg/hive/HiveTableOperations.java","lineNumber":307,"sourceCode":"        updateHiveTable = true;\n        LOG.debug(\"Committing existing table: {}\", fullName);\n      } else {\n        tbl =\n            newHmsTable(\n                tableMetadata.property(HiveCatalog.HMS_TABLE_OWNER, HiveHadoopUtil.currentUser()));\n        LOG.debug(\"Committing new table: {}\", fullName);\n      }\n\n      tbl.setSd(\n          HiveOperationsBase.storageDescriptor(\n              tableMetadata.schema(),\n              tableMetadata.location(),\n              hiveEngineEnabled)); // set to pickup any schema changes\n\n      String metadataLocation = tbl.getParameters().get(METADATA_LOCATION_PROP);\n      String baseMetadataLocation = base != null ? base.metadataFileLocation() : null;\n      if (!Objects.equals(baseMetadataLocation, metadataLocation)) {\n        throw new CommitFailedException(\n            \"Cannot commit: Base metadata location '%s' is not same as the current table metadata location '%s' for %s.%s\",\n            baseMetadataLocation, metadataLocation, database, tableName);\n      }\n\n      // get Iceberg props that have been removed\n      Set<String> removedProps = Collections.emptySet();\n      if (base != null) {\n        removedProps =\n            base.properties().keySet().stream()\n                .filter(key -> !tableMetadata.properties().containsKey(key))\n                .collect(Collectors.toSet());\n\n        Preconditions.checkArgument(\n            !removedProps.contains(TableProperties.ENCRYPTION_TABLE_KEY),\n            \"Cannot remove key ID from an encrypted table\");\n\n        Preconditions.checkArgument(\n            Objects.equals(","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/hive-metastore/src/main/java/org/apache/iceberg/hive/HiveTableOperations.java#L289-L325","documentation":"HiveTableOperations.doCommit performs an optimistic-concurrency check before altering the Hive metastore table: the base metadata file location the commit was started from must equal the metadata_location parameter currently stored in the HMS table. If another process committed in between, the base is stale and this CommitFailedException is thrown so the caller can retry the whole operation.","triggerScenarios":"Calling HiveTableOperations.doCommit (e.g. via Table.refresh/commit, append, overwrite) when another writer updated the table's metadata_location in HMS after the base TableMetadata snapshot was read; this test path runs with Hive locking disabled (hive.engine/hive lock disabled) so no lock serializes writers.","commonSituations":"Two Spark/Flink jobs or a Spark job and a maintenance tool (rewrite/expire) writing the same Iceberg table concurrently; long-running streams holding stale metadata while a compaction commits; HMS updated manually.","solutions":["Retry the commit: re-read the table (table.refresh()) and re-apply the operation on fresh metadata — CommitFailedException is designed for client-level retry","Enable Hive lock acquisition (iceberg.engine.hive.enabled / lock settings) or use a catalog with atomic commit semantics (HiveCatalog with proper locking, REST, Nessie)","Serialize writers externally so only one job writes to the table at a time","Check the HMS table's metadata_location vs the base to confirm which writer won before retrying"],"exampleFix":"// before\nTable table = catalog.loadTable(ident);\ntable.newAppend().appendFile(file).commit(); // stale base -> CommitFailedException\n// after\nTable table = catalog.loadTable(ident);\ntry {\n  table.newAppend().appendFile(file).commit();\n} catch (CommitFailedException e) {\n  table.refresh();\n  table.newAppend().appendFile(file).commit();\n}","handlingStrategy":"retry","validationCode":"String current = hmsClient.getTable(db, table).getParameters().get(\"metadata_location\");\nif (!Objects.equals(current, table.operations().current().metadataFileLocation())) {\n  table.refresh(); // stale base, reload before writing\n}","typeGuard":null,"tryCatchPattern":"try {\n  table.newAppend().appendFile(f).commit();\n} catch (CommitFailedException e) {\n  table.refresh();\n  table.newAppend().appendFile(f).commit();\n}","preventionTips":["Always wrap Iceberg commits in a CommitFailedException retry loop","Re-read (refresh) the table before each write attempt","Avoid multiple concurrent writers without locking or an atomic-commit catalog","Keep write transactions short to shrink the conflict window"],"tags":["hive-metastore","concurrency","optimistic-locking","commit"],"backgroundTag":"conflicting-config-options","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"}