{"record":{"id":"2c7ba32b73dba6ad","repo":"apache/iceberg","slug":"requirement-failed-s-s-was-created-concurrently","errorCode":null,"errorMessage":"Requirement failed: %s %s was created concurrently","messagePattern":"Requirement failed: (.+?) (.+?) was created concurrently","errorType":"exception","errorClass":"CommitFailedException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/UpdateRequirement.java","lineNumber":115,"sourceCode":"      this.snapshotId = snapshotId;\n    }\n\n    public String refName() {\n      return name;\n    }\n\n    public Long snapshotId() {\n      return snapshotId;\n    }\n\n    @Override\n    public void validate(TableMetadata base) {\n      SnapshotRef ref = base.ref(name);\n      if (ref != null) {\n        String type = ref.isBranch() ? \"branch\" : \"tag\";\n        if (snapshotId == null) {\n          // a null snapshot ID means the ref should not exist already\n          throw new CommitFailedException(\n              \"Requirement failed: %s %s was created concurrently\", type, name);\n        } else if (snapshotId != ref.snapshotId()) {\n          throw new CommitFailedException(\n              \"Requirement failed: %s %s has changed: expected id %s != %s\",\n              type, name, snapshotId, ref.snapshotId());\n        }\n      } else if (snapshotId != null) {\n        throw new CommitFailedException(\n            \"Requirement failed: branch or tag %s is missing, expected %s\", name, snapshotId);\n      }\n    }\n  }\n\n  class AssertLastAssignedFieldId implements UpdateRequirement {\n    private final int lastAssignedFieldId;\n\n    public AssertLastAssignedFieldId(int lastAssignedFieldId) {\n      this.lastAssignedFieldId = lastAssignedFieldId;","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/UpdateRequirement.java#L97-L133","documentation":"This CommitFailedException comes from AssertRefSnapshotId.validate when a requirement asserts that a branch or tag must NOT already exist (snapshotId == null), but the ref is present in the base table metadata. It means another committer created the branch or tag concurrently between when this operation was planned and when the commit was validated. The optimistic-concurrency requirement failed, so the commit was rejected and must be retried against the new table state.","triggerScenarios":"Calling UpdateRequirements.forCreateBranch(name, null) / forCreateTag (snapshotId null) via commit of UpdateTableRequirements when base.ref(name) returns non-null — i.e. the branch/tag was created by a concurrent writer before this commit validated.","commonSituations":"Two clients or jobs run 'ALTER TABLE ... CREATE BRANCH' or fast-forward/management API calls at the same time; a retry after CommitFailedException races with another creator; CI pipelines issuing duplicate create-ref requests against the same table.","solutions":["Re-read the table metadata, check whether the branch/tag already exists and is acceptable, and drop the AssertRefSnapshotId(null) requirement (or use ifNotExists-style handling) before retrying the commit.","Retry the whole update against the refreshed base metadata so requirements are built from current state instead of stale state.","If creation is meant to be unique, treat the exception as 'already created' success and skip the create rather than retrying it.","Serialize ref-creation operations for the table (e.g. application-level locking or a single coordinator) if concurrent creators are frequent."],"exampleFix":"// before\nList<UpdateRequirement> reqs = UpdateRequirements.forCreateBranch(\"audit\");\ntable.manageSnapshots().commit(); // fails if 'audit' exists\n// after\nif (table.refs().get(\"audit\") == null) {\n  table.manageSnapshots().createBranch(\"audit\").commit();\n} // or catch CommitFailedException and treat as already-created","handlingStrategy":"try-catch","validationCode":"if (table.refs().get(\"audit\") != null) {\n  // ref already exists — do not send AssertRefSnapshotId(name, null)\n  return;\n}","typeGuard":"boolean refExists(Table t, String name) { return t.refs().get(name) != null; }","tryCatchPattern":"try {\n  table.manageSnapshots().createBranch(\"audit\").commit();\n} catch (CommitFailedException e) {\n  if (e.getMessage().contains(\"was created concurrently\")) {\n    // treat as already-created; verify ref and continue\n  } else { throw e; }\n}","preventionTips":["Always check table.refs() before issuing create-ref operations","Use ifNotExists-style flags in engines (e.g. Spark CREATE BRANCH IF NOT EXISTS)","Refresh table metadata immediately before committing ref changes","Design creators to be idempotent: catch CommitFailedException and verify outcome"],"tags":["concurrency","commit-failed","iceberg","rest-catalog"],"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"}