apache/iceberg · error · UnsupportedOperationException

Expected truncation width to be tinyint, shortint or int

Error message

Expected truncation width to be tinyint, shortint or int

What it means

In TruncateFunction.bind(), the first argument (truncation width) must be ByteType, ShortType, or IntegerType. bind() throws UnsupportedOperationException if the width field has any other type (long, decimal, string, null, etc.).

Solutions

  1. Use an INT literal: truncate(10, col) — plain integer literals in Spark are INT.
  2. Cast the width: truncate(cast(width_col AS INT), col).
  3. Cast untyped NULL: truncate(cast(NULL AS INT), col).
  4. Check the width expression's type with typeof() to confirm.

Example fix

// before
SELECT iceberg.truncate(100L, id) FROM t;
// after
SELECT iceberg.truncate(100, id) FROM t;
-- or
SELECT iceberg.truncate(CAST(width_col AS INT), id) FROM t;
Defensive patterns

Strategy: validation

Validate before calling

val widthType = widthExpr.dataType
require(widthType == ByteType || widthType == ShortType || widthType == IntegerType,
  s"truncate width must be tinyint/short/int, got $widthType")

Type guard

def isSupportedWidth(t: DataType): Boolean =
  t == ByteType || t == ShortType || t == IntegerType

Prevention

When it happens

Trigger: Calling iceberg.truncate(10L, col), truncate('10', col), truncate(cast(10 as bigint), col), or passing a NULL without a cast.

Common situations: Numeric literals read as BIGINT from config-driven SQL; width pulled from a BIGINT column; width parameter bound from application code as a 64-bit value.

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


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

Appendix: source

Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/functions/TruncateFunction.java:72

public class TruncateFunction implements UnboundFunction {

  private static final int WIDTH_ORDINAL = 0;
  private static final int VALUE_ORDINAL = 1;

  private static final Set<DataType> SUPPORTED_WIDTH_TYPES =
      ImmutableSet.of(DataTypes.ByteType, DataTypes.ShortType, DataTypes.IntegerType);

  @Override
  public BoundFunction bind(StructType inputType) {
    if (inputType.size() != 2) {
      throw new UnsupportedOperationException("Wrong number of inputs (expected width and value)");
    }

    StructField widthField = inputType.fields()[WIDTH_ORDINAL];
    StructField valueField = inputType.fields()[VALUE_ORDINAL];

    if (!SUPPORTED_WIDTH_TYPES.contains(widthField.dataType())) {
      throw new UnsupportedOperationException(
          "Expected truncation width to be tinyint, shortint or int");
    }

    DataType valueType = valueField.dataType();
    if (valueType instanceof ByteType) {
      return new TruncateTinyInt();
    } else if (valueType instanceof ShortType) {
      return new TruncateSmallInt();
    } else if (valueType instanceof IntegerType) {
      return new TruncateInt();
    } else if (valueType instanceof LongType) {
      return new TruncateBigInt();
    } else if (valueType instanceof DecimalType) {
      return new TruncateDecimal(
          ((DecimalType) valueType).precision(), ((DecimalType) valueType).scale());
    } else if (valueType instanceof StringType) {
      return new TruncateString();
    } else if (valueType instanceof BinaryType) {

View on GitHub (pinned to 86d9c8fc54)