apache/iceberg · error · IllegalStateException
Staging snapshot %s on branch '%s' contains a V2 positional
Error message
Staging snapshot %s on branch '%s' contains a V2 positional delete file (%s); equality delete conversion expects a V3 staging branch written by Flink, which produces only deletion vectors for deletes.
What it means
EqualityConvertPlanner.retrieveStagingFiles expects every delete file on the staging branch to be either an equality delete file or a deletion vector (V3). Finding a V2 positional delete file means the staging branch content does not match what the converter supports, so it fails fast naming the offending file location.
Source
Thrown at flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/maintenance/operator/EqualityConvertPlanner.java:584
for (DeleteFile deleteFile : changes.addedDeleteFiles()) {
if (deleteFile.content() == FileContent.EQUALITY_DELETES) {
Set<Integer> deleteFieldIds = Sets.newHashSet(deleteFile.equalityFieldIds());
Preconditions.checkState(
deleteFieldIds.equals(eqFieldIds),
"Staging snapshot %s on branch '%s' contains an equality delete file %s with "
+ "equalityFieldIds=%s, which does not match the configured eqFieldIds=%s. "
+ "The writer must use the same equality field IDs as the converter.",
stagingSnapshot.snapshotId(),
stagingBranch,
deleteFile.location(),
deleteFieldIds,
eqFieldIds);
validateDeleteSpecPartitionColumns(stagingSnapshot, deleteFile);
eqDeleteFiles.add(deleteFile);
} else if (ContentFileUtil.isDV(deleteFile)) {
stagingDVFiles.add(deleteFile);
} else {
throw new IllegalStateException(
String.format(
"Staging snapshot %s on branch '%s' contains a V2 positional delete file (%s); "
+ "equality delete conversion expects a V3 staging branch written by Flink, "
+ "which produces only deletion vectors for deletes.",
stagingSnapshot.snapshotId(), stagingBranch, deleteFile.location()));
}
}
return new StagingInputs(newDataFiles, stagingDVFiles, eqDeleteFiles);
}
private void validateDeleteSpecPartitionColumns(Snapshot stagingSnapshot, DeleteFile deleteFile) {
PartitionSpec spec = table.specs().get(deleteFile.specId());
for (PartitionField field : spec.fields()) {
Preconditions.checkState(
eqFieldIds.contains(field.sourceId()),
"Staging snapshot %s on branch '%s' contains an equality delete file %s under spec %s, "
+ "which partitions by field '%s' (source id %s) that is not an equality field %s. "View on GitHub (pinned to 86d9c8fc54)
Solutions
- Ensure all writers to the staging branch use format version 3 with DVs (Flink writer for this feature).
- Dedicate the staging branch to the converter and stop legacy V2 writers from targeting it.
- Repoint stagingBranch to a fresh, empty branch and start a new conversion cycle.
- Convert or remove existing positional deletes on the branch (e.g., via rewrite delete files on the main branch) before planning.
Defensive patterns
Strategy: validation
Validate before calling
// ensure all delete files on the staging branch are eq-deletes or DVs
for (DeleteFile f : stagingDeleteFiles) {
if (!ContentFileUtil.isDV(f) && f.content() != FileContent.EQUALITY_DELETES) {
throw new IllegalStateException("Unsupported delete file on staging: " + f.location());
}
} Prevention
- Ensure the table format version is 3 and all staging writers emit DVs.
- Block legacy v2 writers from the staging branch.
- Verify table.formatVersion() before enabling the converter.
- Inspect staging-branch files for POSITION_DELETES content before each cycle.
When it happens
Trigger: inputs() -> retrieveStagingFiles iterates the staging snapshot's delete files and hits a ContentFile that is neither an equality delete nor a DV — a positional delete file written by a V2 writer on the staging branch.
Common situations: Pointing stagingBranch at a branch that received writes from an older V2-format writer (e.g., legacy Spark/Flink jobs producing position deletes); format-version migration leftovers on the branch.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- V2 positional delete file %s attached to main data file %s;
- Staging snapshot %s on branch '%s' contains a V2 positional
- V2 positional delete file %s attached to main data file %s;
- Staging snapshot %s on branch '%s' contains a V2 positional
- V2 positional delete file %s attached to main data file %s;
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/a0ce7927942b5767.
Report an issue: GitHub.