apache/iceberg · error · UnsupportedOperationException
Unsupported metadata stats field ID: ${statId}
Error message
Unsupported metadata stats field ID: ${statId} What it means
Stats files encode metadata column statistics using synthetic (reserved) field IDs that must fall into known ranges (last-updated-sequence-number, row-id, and content-stats ranges). toFieldId translates a stat ID back to a real field ID; an ID outside every known range cannot be mapped, so the parser refuses it. This protects forward compatibility: unknown reserved IDs mean the stats were written by a newer spec version the reader doesn't understand.
Source
Thrown at core/src/main/java/org/apache/iceberg/StatsUtil.java:110
/**
* Return the field ID corresponding to the stats field ID.
*
* @param statId the field ID of a field stats struct or field within a stats struct
* @return ID of the corresponding table field
* @throws IllegalArgumentException if the stats ID is not valid
* @throws UnsupportedOperationException if the stats ID is for an unsupported metadata field
*/
static int toFieldId(int statId) {
Preconditions.checkArgument(isValidStatId(statId), "Invalid stats field ID: %s", statId);
if (statId < CONTENT_STATS_RANGE_START) {
if (inBaseIdRange(LAST_UPDATED_SEQ_NUM_BASE_ID, statId)) {
return MetadataColumns.LAST_UPDATED_SEQUENCE_NUMBER.fieldId();
} else if (inBaseIdRange(ROW_ID_BASE_ID, statId)) {
return MetadataColumns.ROW_ID.fieldId();
} else {
throw new UnsupportedOperationException("Unsupported metadata stats field ID: " + statId);
}
}
return (statId - CONTENT_STATS_RANGE_START) / NUM_RESERVED_FIELD_STATS_IDS;
}
/**
* Return the stats offset of a stats field ID.
*
* @param statId the field ID of a field stats struct or field within a stats struct
* @return offset that identifies the stored metric, or 0 for a stats struct's ID
* @throws IllegalArgumentException if the stats ID is not valid
* @throws UnsupportedOperationException if the stats ID is for an unsupported metadata field
*/
static int statOffset(int statId) {
Preconditions.checkArgument(isValidStatId(statId), "Invalid stats field ID: %s", statId);
return statId % NUM_RESERVED_FIELD_STATS_IDS;View on GitHub (pinned to 86d9c8fc54)
Solutions
- Upgrade Iceberg to a version that knows the reserved stat ID range used by the stats file
- Regenerate the stats file with a compatible writer so it only uses recognized stat IDs
- Verify the stats file matches the table format version and spec you are reading with
- Skip/ignore the unrecognized stats entries instead of failing plan if your use case tolerates missing stats
Defensive patterns
Strategy: try-catch
Validate before calling
boolean knownReservedId(int statId) {
return statId >= CONTENT_STATS_RANGE_START
|| inRange(LAST_UPDATED_SEQ_NUM_BASE_ID, statId)
|| inRange(ROW_ID_BASE_ID, statId);
} Try / catch
try { long fieldId = StatsUtil.toFieldId(statId); }
catch (UnsupportedOperationException e) {
LOG.warn("Unknown reserved stats ID {} from a newer writer; skipping", statId);
} Prevention
- Keep reader and writer Iceberg versions in sync across the deployment
- Never hand-craft reserved stat IDs; use spec-assigned ranges only
- Validate stats files after generation with a round-trip read
- Treat unrecognized stat IDs as 'stats unavailable', not fatal, where possible
When it happens
Trigger: Reading a stats (puffin/dv/placeholder-statistics) file whose metadata field statId is below CONTENT_STATS_RANGE_START but not within the LAST_UPDATED_SEQ_NUM or ROW_ID reserved ranges — i.e. StatsUtil.toFieldId(statId) called with an unrecognized reserved ID.
Common situations: Stats files written by a newer Iceberg version with additional reserved metadata stats IDs read by an older reader; hand-edited or corrupted stats files; custom tooling that invents stat IDs instead of using the spec-assigned ranges.
Related errors
- Cannot apply unsupported transform: %s
- Unsupported content type for manifests:
- %s does not implement deleteFile
- %s does not implement addFile
- %s does not implement dataSequenceNumber
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/6d51e1bc10ce897c.
Report an issue: GitHub.