apache/iceberg · error · UnsupportedOperationException
Unsupported stats offset:
Error message
Unsupported stats offset:
What it means
FieldStatsStruct.getOffset maps stat offsets (UPPER_BOUND, TIGHT_BOUNDS, VALUE_COUNT, NULL_VALUE_COUNT, NAN_VALUE_COUNT, AVG_VALUE_SIZE) to field values; an unrecognized offset throws UnsupportedOperationException('Unsupported stats offset: ' + offset). Since offsets come from posToOffset (built from a projected stats struct schema), this indicates the projection contains a field position with no corresponding stats offset.
Source
Thrown at core/src/main/java/org/apache/iceberg/FieldStatsStruct.java:195
public Integer avgValueSizeInBytes() {
return avgValueSize;
}
@Override
public int size() {
return struct.fields().size();
}
private Object getOffset(int offset) {
return switch (offset) {
case StatsUtil.LOWER_BOUND_OFFSET -> lowerBound();
case StatsUtil.UPPER_BOUND_OFFSET -> upperBound();
case StatsUtil.TIGHT_BOUNDS_OFFSET -> tightBounds;
case StatsUtil.VALUE_COUNT_OFFSET -> valueCount;
case StatsUtil.NULL_VALUE_COUNT_OFFSET -> nullValueCount;
case StatsUtil.NAN_VALUE_COUNT_OFFSET -> nanValueCount;
case StatsUtil.AVG_VALUE_SIZE_OFFSET -> avgValueSize;
default -> throw new UnsupportedOperationException("Unsupported stats offset: " + offset);
};
}
@Override
public <C> C get(int pos, Class<C> javaClass) {
return javaClass.cast(getOffset(posToOffset[pos]));
}
private void setOffset(int offset, Object value) {
switch (offset) {
case StatsUtil.LOWER_BOUND_OFFSET -> setLowerBound(value);
case StatsUtil.UPPER_BOUND_OFFSET -> setUpperBound(value);
case StatsUtil.TIGHT_BOUNDS_OFFSET -> this.tightBounds = (Boolean) value;
case StatsUtil.VALUE_COUNT_OFFSET -> this.valueCount = (Long) value;
case StatsUtil.NULL_VALUE_COUNT_OFFSET -> this.nullValueCount = (Long) value;
case StatsUtil.NAN_VALUE_COUNT_OFFSET -> this.nanValueCount = (Long) value;
case StatsUtil.AVG_VALUE_SIZE_OFFSET -> this.avgValueSize = (Integer) value;
default -> throw new UnsupportedOperationException("Unsupported stats offset: " + offset);View on GitHub (pinned to 86d9c8fc54)
Solutions
- Ensure the reader and writer Iceberg versions agree on the stats file schema; re-generate the statistics file with the current version.
- Verify posToOffset is built by StatsUtil.posToOffset(...) from the same type used to create the FieldStatsStruct, not by custom code.
- Print the offending offset and compare against StatsUtil offset constants to identify the unexpected field.
- Upgrade Iceberg if the stats file uses a newer schema version than the reader supports.
Example fix
// before: hand-built offset array
int[] posToOffset = {0, 1, 2, 99}; // 99 is not a known stats offset
// after: derive offsets from StatsUtil
int[] posToOffset = StatsUtil.posToOffset(partitionType, statsType); Defensive patterns
Strategy: validation
Validate before calling
for (int offset : posToOffset) {
if (!StatsUtil.isKnownOffset(offset)) {
throw new IllegalArgumentException("Unsupported stats offset in projection: " + offset);
}
} Try / catch
try {
C v = statsStruct.get(pos, javaClass);
} catch (UnsupportedOperationException e) {
if (e.getMessage().startsWith("Unsupported stats offset")) {
// regenerate the statistics projection with the current StatsUtil
} else throw e;
} Prevention
- Always build posToOffset via StatsUtil, never manually.
- Regenerate stats files when upgrading Iceberg versions.
- Match reader version to the writer version of statistics files.
When it happens
Trigger: Calling get(pos, Class) where posToOffset[pos] was computed from a partition/field-stats schema that includes a field outside the known stats offsets — typically a malformed projection produced by StatsUtil when the schema and stats file version disagree.
Common situations: Reading a statistics file written by a different Iceberg version whose StatsUtil offsets changed; custom code constructing posToOffset manually; partition fields added in newer spec versions but the reader is older.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- %s doesn't implement copyWithStats
- Updating statistics is not supported by + getClass().getName
- Updating statistics is not supported by + getClass().getName
- this.getClass().getName() + " does not implement computeTabl
- Cannot update statistics of a %s table
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/80ab8e2d01c29f7c.
Report an issue: GitHub.