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
The truncation width argument must be ByteType (tinyint), ShortType (shortint/smallint), or IntegerType (int). `bind` throws this UnsupportedOperationException when the width field has any other type (e.g. long, string, decimal). The width controls how many bytes/characters to keep and is intentionally restricted.
Source
Thrown at spark/v3.5/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)
Solutions
- Cast the width to int: `truncate(CAST(20 AS INT), col)`.
- Use an int-binding literal: `truncate(20, col)` in versions where integer literals are INT by default.
- In code, pass an IntegerType literal (e.g. functions.lit(20)) rather than a long.
Example fix
// before
spark.sql("SELECT truncate(10L, s) FROM t")
// after
spark.sql("SELECT truncate(CAST(10 AS INT), s) FROM t") Defensive patterns
Strategy: validation
Validate before calling
// ensure the width literal binds as int
spark.sql("SELECT typeof(CAST(10 AS INT))").show(); // 'int'
// or in code: functions.lit(10) typed as int, never lit(10L) Try / catch
try { df.select(functions.callUDF("truncate", functions.lit(10), functions.col("s"))); } catch (UnsupportedOperationException e) { if (e.getMessage().contains("tinyint, shortint or int")) { /* cast width to INT */ } throw e; } Prevention
- CAST the width to INT when literal inference is uncertain.
- Never pass long/string/decimal widths.
- Verify inferred literal types with typeof() during query development.
When it happens
Trigger: Calling `truncate` with a width literal Spark infers as BIGINT (e.g. `truncate(10L, col)`), or passing a width column of type long/string/decimal.
Common situations: Spark literal inference producing BIGINT widths; programmatic calls passing Long instead of Int; copying examples from engines where literal defaults differ.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- 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
- Expected number of buckets to be tinyint, shortint or int
- Expected column to be date, tinyint, smallint, int, bigint,
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/a970f46f770756bf.
Report an issue: GitHub.