{"record":{"id":"72c037d0cfc3f9bb","repo":"apache/iceberg","slug":"the-table-s-s-has-been-modified-concurrently","errorCode":null,"errorMessage":"The table %s.%s has been modified concurrently","messagePattern":"The table (.+?)\\.(.+?) has been modified concurrently","errorType":"exception","errorClass":"CommitFailedException","httpStatus":null,"severity":"error","filePath":"hive-metastore/src/main/java/org/apache/iceberg/hive/HiveTableOperations.java","lineNumber":393,"sourceCode":"                  + \"table 'HIVE_LOCKS' does not exist. This can occur when using an embedded metastore which does not \"\n                  + \"support transactions. To fix this use an alternative metastore.\",\n              e);\n        }\n\n        commitStatus = BaseMetastoreOperations.CommitStatus.UNKNOWN;\n        if (e.getMessage() != null\n            && e.getMessage()\n                .contains(\n                    \"The table has been modified. The parameter value for key '\"\n                        + HiveTableOperations.METADATA_LOCATION_PROP\n                        + \"' is\")) {\n          // It's possible the HMS client incorrectly retries a successful operation, due to network\n          // issue for example, and triggers this exception. So we need double-check to make sure\n          // this is really a concurrent modification. Hitting this exception means no pending\n          // requests, if any, can succeed later, so it's safe to check status in strict mode\n          commitStatus = checkCommitStatusStrict(newMetadataLocation, tableMetadata);\n          if (commitStatus == BaseMetastoreOperations.CommitStatus.FAILURE) {\n            throw new CommitFailedException(\n                e, \"The table %s.%s has been modified concurrently\", database, tableName);\n          }\n        } else {\n          LOG.error(\n              \"Cannot tell if commit to {}.{} succeeded, attempting to reconnect and check.\",\n              database,\n              tableName,\n              e);\n          commitStatus = checkCommitStatus(newMetadataLocation, tableMetadata);\n        }\n\n        switch (commitStatus) {\n          case SUCCESS:\n            break;\n          case FAILURE:\n            throw e;\n          case UNKNOWN:\n            throw new CommitStateUnknownException(e);","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/hive-metastore/src/main/java/org/apache/iceberg/hive/HiveTableOperations.java#L375-L411","documentation":"HMS reported the table was already modified (e.g. InvalidOperationException from a failed alter), and before declaring failure doCommit re-checks the commit status in strict mode by comparing the stored metadata_location with the new one. If the check confirms the location does not match this commit, a CommitFailedException 'modified concurrently' is thrown — the commit did not land because another writer changed the table first.","triggerScenarios":"doCommit's persistTable throws an exception interpreted as concurrent modification (already-moved metadata_location); the subsequent checkCommitStatusStrict finds metadata_location != newMetadataLocation and status FAILURE.","commonSituations":"Concurrent Iceberg committers via HiveCatalog without sufficient locking; HMS client retry of a successful alter masking real concurrency; two engines (Spark + Flink) writing the same table.","solutions":["Retry the whole operation with refreshed table metadata (CommitFailedException is retriable)","Enable Hive lock acquisition so concurrent committers are serialized","Inspect table history/metadata_location to identify the competing writer","Move to a catalog with stronger commit semantics if contention is frequent"],"exampleFix":"// before\n table.newOverwrite().deleteFile(f).commit(); // may fail under concurrency\n// after\nRetryUtil.retry(CommitFailedException.class, 3, () -> {\n  table.refresh();\n  table.newOverwrite().deleteFile(f).commit();\n});","handlingStrategy":"retry","validationCode":"String loc = hmsClient.getTable(db, tbl).getParameters().get(\"metadata_location\");\nif (!Objects.equals(loc, expectedBaseLocation)) table.refresh();","typeGuard":null,"tryCatchPattern":"try {\n  table.newAppend().appendFile(f).commit();\n} catch (CommitFailedException e) {\n  table.refresh();\n  // retry with backoff, bounded attempts\n}","preventionTips":["Retry CommitFailedException with fresh metadata and backoff","Enable Hive locking to serialize committers","Minimize concurrent writers per table","Audit which jobs write to shared tables"],"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-14T16:17:12.679Z"}