apache/iceberg · error · ValidationException
Cannot apply non-unique WAP ID. Found multiple snapshots wit
Error message
Cannot apply non-unique WAP ID. Found multiple snapshots with WAP ID '%s'
What it means
PublishChangesProcedure cherry-picks a staged (WAP) snapshot identified by its write.wap.id property. ValidationException is thrown when more than one snapshot in the table carries the same WAP ID, because publishing would be ambiguous — the procedure refuses to guess which snapshot to publish.
Source
Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/procedures/PublishChangesProcedure.java:102
public ProcedureParameter[] parameters() {
return PARAMETERS;
}
@Override
public Iterator<Scan> call(InternalRow args) {
ProcedureInput input = new ProcedureInput(spark(), tableCatalog(), PARAMETERS, args);
Identifier tableIdent = input.ident(TABLE_PARAM);
String wapId = input.asString(WAP_ID_PARAM);
return modifyIcebergTable(
tableIdent,
table -> {
Snapshot matchingSnap = null;
for (Snapshot snap : table.snapshots()) {
if (wapId.equals(WapUtil.stagedWapId(snap))) {
if (matchingSnap != null) {
throw new ValidationException(
"Cannot apply non-unique WAP ID. Found multiple snapshots with WAP ID '%s'",
wapId);
} else {
matchingSnap = snap;
}
}
}
if (matchingSnap == null) {
throw new ValidationException("Cannot apply unknown WAP ID '%s'", wapId);
}
long wapSnapshotId = matchingSnap.snapshotId();
table.manageSnapshots().cherrypick(wapSnapshotId).commit();
Snapshot currentSnapshot = table.currentSnapshot();
InternalRow outputRow = newInternalRow(wapSnapshotId, currentSnapshot.snapshotId());
return asScanIterator(OUTPUT_TYPE, outputRow);
});View on GitHub (pinned to 86d9c8fc54)
Solutions
- Generate a unique wap.id per write job (e.g. UUID) instead of reusing values
- Expire or delete the earlier duplicate staged snapshots, then retry publish_changes
- Cherry-pick the intended snapshot manually via table.manageSnapshots().cherrypick(snapshotId) to disambiguate
- List snapshots (SELECT * FROM table.snapshots) to find the duplicates before publishing
Example fix
// before
spark.conf.set("write.wap.id", "fixed-id"); // reused every run
// after
spark.conf.set("write.wap.id", java.util.UUID.randomUUID().toString()); Defensive patterns
Strategy: validation
Validate before calling
// detect duplicate WAP IDs before publishing
val dups = spark.table("cat.db.t.snapshots").where("properties[\"write.wap.id\"] = wapId").count()
if (dups > 1) fail("non-unique WAP ID") Try / catch
try { spark.sql(call) } catch { case e: ValidationException if e.getMessage.contains("non-unique WAP ID") => /* expire duplicates or cherry-pick manually */ } Prevention
- Generate a unique write.wap.id (UUID) per write job
- Expire staged snapshots after publishing
- Never hard-code WAP IDs in reusable pipelines
When it happens
Trigger: Calling CALL cat.system.publish_changes(table => ..., id => 'X') when two or more staged snapshots were written with the same write.wap.id value (e.g. reusing a WAP ID across retries or jobs without expiring/cherry-picking earlier ones).
Common situations: Hard-coding the same wap.id in a CI pipeline across repeated runs; retrying a failed Spark write with the same wap.id after the first attempt actually succeeded as a staged snapshot; long-lived staged snapshots never published or expired.
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
- Cannot apply non-unique WAP ID. Found multiple snapshots wit
- Cannot apply unknown WAP ID '${wapId}'
- Cannot apply non-unique WAP ID. Found multiple snapshots wit
- Cannot apply unknown WAP ID '%s'
- Couldn't load table '${ident}' in catalog '${tableCatalog.na
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/3e0d7c2a25fb64fb.
Report an issue: GitHub.