apache/iceberg · error · UnsupportedOperationException
Expected value to be date or timestamp: ${valueType.catalogS
Error message
Expected value to be date or timestamp: ${valueType.catalogString()} What it means
YearsFunction is a Spark Iceberg vectorized function that converts date/timestamp values to a year count (Iceberg 'years' transform). Binding validates the input Spark DataType; when the argument is not DateType, TimestampType, or TimestampNTZType, binding fails with this UnsupportedOperationException listing the offending type's catalog string.
Source
Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/functions/YearsFunction.java:46
import org.apache.spark.sql.types.TimestampType;
/**
* A Spark function implementation for the Iceberg year transform.
*
* <p>Example usage: {@code SELECT system.years('source_col')}.
*/
public class YearsFunction extends UnaryUnboundFunction {
@Override
protected BoundFunction doBind(DataType valueType) {
if (valueType instanceof DateType) {
return new DateToYearsFunction();
} else if (valueType instanceof TimestampType) {
return new TimestampToYearsFunction();
} else if (valueType instanceof TimestampNTZType) {
return new TimestampNtzToYearsFunction();
} else {
throw new UnsupportedOperationException(
"Expected value to be date or timestamp: " + valueType.catalogString());
}
}
@Override
public String description() {
return name()
+ "(col) - Call Iceberg's year transform\n"
+ " col :: source column (must be date or timestamp)";
}
@Override
public String name() {
return "years";
}
private abstract static class BaseToYearsFunction extends BaseScalarFunction<Integer> {
@OverrideView on GitHub (pinned to 86d9c8fc54)
Solutions
- Cast the input column to date or timestamp before calling years(), e.g. years(to_date(col)) or years(col.cast("timestamp")).
- If the source is a string, use to_date or to_timestamp with an explicit format string.
- Verify the column's actual Spark type with df.printSchema() and fix the upstream schema if it drifted.
Example fix
// before SELECT years(event_date_str) FROM events; // after SELECT years(to_date(event_date_str, 'yyyy-MM-dd')) FROM events;
Defensive patterns
Strategy: validation
Validate before calling
val allowed = Seq("date", "timestamp", "timestamp_ntz")
require(allowed.contains(df.schema("event_ts").dataType.typeName), "years() needs date/timestamp column") Type guard
def isDateOrTimestamp(dt: org.apache.spark.sql.types.DataType): Boolean =
dt match {
case _: org.apache.spark.sql.types.DateType => true
case _: org.apache.spark.sql.types.TimestampType => true
case _: org.apache.spark.sql.types.TimestampNTZType => true
case _ => false
} Prevention
- Check df.printSchema() before applying transform functions
- Cast string dates explicitly with to_date/to_timestamp
- Guard shared SQL templates against schema drift
When it happens
Trigger: Calling years(col) in Spark SQL or DataFrame API with an input column whose type is not a date or timestamp — e.g. a string, int, or decimal column passed to the years() function.
Common situations: Passing a string that looks like a date ('2024-01-01') without casting; using years() on a numeric epoch column; schema drift after upstream changes made the column a string.
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 width to be tinyint, shortint or int
- Expected value to be date or timestamp:
- Table does not implement %s: %s (%s)
- Cannot convert type to SQL: %s
- Cannot convert bound predicates to SQL
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/65a237cedb1573ec.
Report an issue: GitHub.