apache/iceberg · error · CommitFailedException

Requirement failed: last assigned partition id changed: expe

Error message

Requirement failed: last assigned partition id changed: expected id %s != %s

What it means

Thrown by AssertLastAssignedPartitionId.validate when the requirement's lastAssignedPartitionId does not match base.lastAssignedPartitionId() (the highest partition field ID assigned in any spec). Partition field IDs are also monotonic and must never be reused; the assertion detects concurrent partition-spec evolution (AddPartitionField/RemovePartitionField) between planning and commit.

Source

Thrown at core/src/main/java/org/apache/iceberg/UpdateRequirement.java:185

      }
    }
  }

  class AssertLastAssignedPartitionId implements UpdateRequirement {
    private final int lastAssignedPartitionId;

    public AssertLastAssignedPartitionId(int lastAssignedPartitionId) {
      this.lastAssignedPartitionId = lastAssignedPartitionId;
    }

    public int lastAssignedPartitionId() {
      return lastAssignedPartitionId;
    }

    @Override
    public void validate(TableMetadata base) {
      if (base != null && base.lastAssignedPartitionId() != lastAssignedPartitionId) {
        throw new CommitFailedException(
            "Requirement failed: last assigned partition id changed: expected id %s != %s",
            lastAssignedPartitionId, base.lastAssignedPartitionId());
      }
    }
  }

  class AssertDefaultSpecID implements UpdateRequirement {
    private final int specId;

    public AssertDefaultSpecID(int specId) {
      this.specId = specId;
    }

    public int specId() {
      return specId;
    }

    @Override

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Refresh the table metadata, rebuild requirements with the current lastAssignedPartitionId, and retry.
  2. Re-apply the partition-spec change against the refreshed spec so new partition field IDs are assigned from the current max.
  3. Coordinate partition evolution through a single migration job/owner to avoid racing writers.
  4. Catch CommitFailedException and retry with backoff; this is the intended recovery path for concurrent-commit conflicts.

Example fix

// before
UpdateRequirement req = new UpdateRequirement.AssertLastAssignedPartitionId(7); // now 9
// after
table.refresh();
UpdateRequirement req = new UpdateRequirement.AssertLastAssignedPartitionId(
    table.spec().lastAssignedPartitionId());
Defensive patterns

Strategy: retry

Validate before calling

table.refresh();
if (table.spec().lastAssignedPartitionId() != assertedPartitionId) {
  throw new IllegalStateException("Partition spec evolved; re-plan");
}

Try / catch

try {
  commitPartitionEvolution();
} catch (CommitFailedException e) {
  if (e.getMessage().contains("last assigned partition id changed")) {
    table.refresh();
    reapplySpecChange(table);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Committing updates (e.g. ReplacePartitionSpec or UpdatePartitionSpec flows) whose requirements include AssertLastAssignedPartitionId when base.lastAssignedPartitionId() differs — another writer added or removed partition fields concurrently.

Common situations: Two jobs repartition the table at once; a partition-evolution migration racing with routine partition-field additions; REST catalog commits built from a stale table version where another client already extended the spec.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/8f3f4cd281c8bbd8. Report an issue: GitHub.