apache/iceberg · error · CommitFailedException

Requirement failed: default partition spec changed…

Error message

Requirement failed: default partition spec changed: expected id %s != %s

What it means

Thrown by AssertDefaultSpecId.validate when the requirement's specId differs from base.defaultSpecId(). This requirement asserts the table's default partition spec is unchanged since the update was planned. A mismatch means a concurrent writer switched the default spec (partition evolution), so the commit is rejected to prevent writing data under assumptions about the wrong spec.

Solutions

  1. Refresh metadata, read base.defaultSpecId(), rebuild the requirements, and retry the commit.
  2. Re-evaluate the operation under the new default spec — writes planned for the old spec may need re-partitioning before retry.
  3. Gate partition-evolution changes behind a single coordinated job so concurrent default-spec switches cannot occur.
  4. Catch CommitFailedException and retry the update against fresh metadata with backoff.

Example fix

// before
UpdateRequirement req = new UpdateRequirement.AssertDefaultSpecId(0); // default now spec 1
// after
table.refresh();
UpdateRequirement req = new UpdateRequirement.AssertDefaultSpecId(
    table.spec().specId());
Defensive patterns

Strategy: retry

Validate before calling

table.refresh();
if (table.spec().specId() != expectedDefaultSpecId) {
  throw new IllegalStateException("Default spec changed; re-plan writes");
}

Try / catch

try {
  commitWithRequirements(reqs);
} catch (CommitFailedException e) {
  if (e.getMessage().contains("default partition spec changed")) {
    table.refresh();
    reqs = rebuildRequirements(table);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Committing updates with AssertDefaultSpecId when base.defaultSpecId() != specId — another job ran UpdatePartitionSpec (replacing the default spec) or reset the default spec concurrently.

Common situations: A partition-evolution migration running while writers commit other metadata changes; two admin jobs both altering partitioning; commits from a client whose cached metadata predates a spec change; REST catalog conflicts between independent services managing the table.

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/ebe763eb0c5ca4ef. Report an issue: GitHub.

Appendix: source

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

      }
    }
  }

  class AssertDefaultSpecID implements UpdateRequirement {
    private final int specId;

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

    public int specId() {
      return specId;
    }

    @Override
    public void validate(TableMetadata base) {
      if (specId != base.defaultSpecId()) {
        throw new CommitFailedException(
            "Requirement failed: default partition spec changed: expected id %s != %s",
            specId, base.defaultSpecId());
      }
    }
  }

  class AssertDefaultSortOrderID implements UpdateRequirement {
    private final int sortOrderId;

    public AssertDefaultSortOrderID(int sortOrderId) {
      this.sortOrderId = sortOrderId;
    }

    public int sortOrderId() {
      return sortOrderId;
    }

    @Override

View on GitHub (pinned to 86d9c8fc54)