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

Input validation in BucketFunction.bind: the first argument (number of buckets) has a Spark type outside the allowed set {byte, short, int}; the %s names the field. Note the companion guard rejects arity != 2 first, and per the Javadoc the bucket count is not re-validated in codegen, so it must be positive to be meaningful.

Source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/functions/BucketFunction.java:71

 * results.
 */
public class BucketFunction implements UnboundFunction {

  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);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Cast the bucket count to INT: system.bucket(CAST(n AS INT), value)
  2. Use a plain integer literal: system.bucket(8, value)
  3. If it comes from a long variable, narrow it with Int.satisfied or an explicit cast in Scala/Java code before invoking the function builder

Example fix

// before
spark.sql("SELECT system.bucket(CAST(8 AS BIGINT), id) FROM tbl")
// after
spark.sql("SELECT system.bucket(8, id) FROM tbl")
Defensive patterns

Strategy: validation

Validate before calling

-- numBuckets must be BYTE/SHORT/INT
SELECT system.bucket(CAST(n AS INT), id) FROM tbl;

Prevention

When it happens

Trigger: Calling system.bucket(numBuckets, value) where numBuckets is a long, decimal, string literal, or non-constant expression typed outside byte/short/int.

Common situations: Passing a BIGINT bucket count from a table property fetched as long; passing a string like '8'; passing a decimal computed value.

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/ab8ecf030cd8504c. Report an issue: GitHub.