apache/iceberg · error · UnsupportedOperationException
Expected number of buckets to be tinyint, shortint or int
Error message
Expected number of buckets to be tinyint, shortint or int
What it means
Type validation in BucketFunction.bind: the first argument (number of buckets) is not one of byte/tinyint, short/smallint or int — the accepted types for the bucket count. The %s names the offending field; cast the bucket count to int before calling system.bucket.
Source
Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/functions/BucketFunction.java:79
private static final int NUM_BUCKETS_ORDINAL = 0;
private static final int VALUE_ORDINAL = 1;
private static final Set<DataType> SUPPORTED_NUM_BUCKETS_TYPES =
ImmutableSet.of(DataTypes.ByteType, DataTypes.ShortType, DataTypes.IntegerType);
@Override
@SuppressWarnings("checkstyle:CyclomaticComplexity")
public BoundFunction bind(StructType inputType) {
if (inputType.size() != 2) {
throw new UnsupportedOperationException(
"Wrong number of inputs (expected numBuckets and value)");
}
StructField numBucketsField = inputType.fields()[NUM_BUCKETS_ORDINAL];
StructField valueField = inputType.fields()[VALUE_ORDINAL];
if (!SUPPORTED_NUM_BUCKETS_TYPES.contains(numBucketsField.dataType())) {
throw new UnsupportedOperationException(
"Expected number of buckets to be tinyint, shortint or int");
}
DataType type = valueField.dataType();
if (type instanceof DateType) {
return new BucketInt(type);
} else if (type instanceof ByteType
|| type instanceof ShortType
|| type instanceof IntegerType) {
return new BucketInt(DataTypes.IntegerType);
} else if (type instanceof LongType) {
return new BucketLong(type);
} else if (type instanceof TimestampType) {
return new BucketLong(type);
} else if (type instanceof TimestampNTZType) {
return new BucketLong(type);
} else if (type instanceof DecimalType) {
return new BucketDecimal(type);View on GitHub (pinned to 86d9c8fc54)
Solutions
- Use a tinyint/short/int value for numBuckets, e.g. system.bucket(8, id) with an int literal
- Cast the numBuckets column: system.bucket(CAST(n AS INT), id)
- Avoid passing bigint columns as bucket counts; compute with int
Example fix
// before SELECT system.bucket(CAST(8 AS BIGINT), id) FROM t; // after SELECT system.bucket(8, id) FROM t;
Defensive patterns
Strategy: type-guard
Validate before calling
if (numBuckets.dataType() != IntegerType && numBuckets.dataType() != ShortType && numBuckets.dataType() != ByteType) {
throw new IllegalArgumentException("numBuckets must be int/short/tinyint");
} Type guard
boolean isIntLike(DataType t) {
return t instanceof ByteType || t instanceof ShortType || t instanceof IntegerType;
} Try / catch
try {
bound = bucketFn.bind(inputType);
} catch (UnsupportedOperationException e) {
throw new IllegalArgumentException("Cast numBuckets to INT", e);
} Prevention
- Use plain int literals for bucket counts (e.g. 8, not 8L)
- Avoid binding bucket counts from bigint columns
- Validate argument types before building bucketed queries
When it happens
Trigger: Invoking system.bucket(...) with numBuckets supplied as a long, decimal, string literal, or a non-integral column type.
Common situations: Passing a long constant like 8L in Scala/Java API; numBuckets read from a bigint column; schema evolution changing the bucket-count column type.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Expected column to be date, tinyint, smallint, int, bigint,
- Expected truncation width to be tinyint, shortint or int
- Expected truncation col to be tinyint, shortint, int, bigint
- Expected value to be date or timestamp: ${valueType.catalogS
- Expected value to be date or timestamp: ${valueType.catalogS
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9c1bcb90ad8c2851.
Report an issue: GitHub.