apache/iceberg · error · IllegalArgumentException
Invalid primitive type for decimal
Error message
Invalid primitive type for decimal: ${primitive} What it means
Thrown by VariantReaderBuilder.variantDecimalType() when a shredded decimal typed_value column's physical type is neither INT32 nor INT64 (DECIMAL4/DECIMAL8). Variant decimal shredding only supports INT32- and INT64-backed decimals; FLBA/BINARY-backed wide decimals are rejected.
Solutions
- Rewrite the shredded decimal so it is backed by INT32 (precision <= 9) or INT64 (precision <= 18).
- Keep high-precision values unshredded inside the Variant binary instead of a typed decimal column.
- Change the producing writer to select an INT32/INT64-backed decimal when shredding.
Example fix
// before
Types.required(PrimitiveTypeName.FIXED_LEN_BYTE_ARRAY).length(16).as(DecimalLogicalType.decimalType(38, 10)).named("typed_value")
// after (precision within 18)
Types.required(PrimitiveTypeName.INT64).as(DecimalLogicalType.decimalType(18, 10)).named("typed_value") Defensive patterns
Strategy: validation
Validate before calling
PrimitiveTypeName p = typedValue.getType().asPrimitiveType().getPrimitiveTypeName();
Preconditions.checkArgument(p == INT32 || p == INT64,
"Shredded decimals must be INT32/INT64-backed, got %s", p); Type guard
boolean isShreddableDecimal(Type t) {
if (!t.isPrimitive()) return false;
PrimitiveTypeName p = t.asPrimitiveType().getPrimitiveTypeName();
return p == PrimitiveTypeName.INT32 || p == PrimitiveTypeName.INT64;
} Try / catch
try {
openVariantReader(schema);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Invalid primitive type for decimal")) {
readUnshreddedVariant(column); // wide decimals stay in variant binary
} else throw e;
} Prevention
- Only shred decimals whose precision fits INT32 (<=9) or INT64 (<=18)
- Keep decimal(>18) values unshredded inside the Variant payload
- Check the physical backing type, not just the decimal logical annotation
When it happens
Trigger: Reading a shredded Variant decimal whose typed_value physical primitive is not INT32/INT64 (e.g. FIXED_LEN_BYTE_ARRAY or BINARY decimal) via primitive() -> variantDecimalType.
Common situations: Writers shredding high-precision decimals (precision > 18) which require FLBA/BINARY backing; tooling defaulting decimals to fixed-length byte arrays; cross-system schemas where decimal backing differs.
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
- Invalid primitive type for decimal
- Invalid bit width for int
- Invalid bit width for int
- Unknown primitive physical type
- Unsupported shredded value type
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/685672924beb862d.
Report an issue: GitHub.
Appendix: source
Thrown at parquet/src/main/java/org/apache/iceberg/parquet/VariantReaderBuilder.java:285
@Override
public Optional<VariantValueReader> visit(UUIDLogicalTypeAnnotation logical) {
VariantValueReader reader =
ParquetVariantReaders.asVariant(PhysicalType.UUID, ParquetValueReaders.uuids(desc));
return Optional.of(reader);
}
private static PhysicalType variantDecimalType(PrimitiveType primitive) {
switch (primitive.getPrimitiveTypeName()) {
case FIXED_LEN_BYTE_ARRAY:
case BINARY:
return PhysicalType.DECIMAL16;
case INT64:
return PhysicalType.DECIMAL8;
case INT32:
return PhysicalType.DECIMAL4;
}
throw new IllegalArgumentException("Invalid primitive type for decimal: " + primitive);
}
}
}
View on GitHub (pinned to 86d9c8fc54)