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 catalog function (years()) that only accepts DATE or TIMESTAMP/TIMESTAMP_NTZ input. During binding, the given input type is checked; any other type (e.g. numeric or string) is rejected because converting an arbitrary value to a year-partition value is undefined. The type's catalogString is appended to help identify the offending type.
Source
Thrown at spark/v4.0/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 column to date or timestamp before applying years(): years(cast(epoch_col as timestamp)).
- Parse string columns with to_date()/to_timestamp() before passing to years().
- Verify the column's actual type with DESCRIBE TABLE and fix the ingestion schema.
- If you just want the calendar year as an int, use Spark's built-in year(col) function instead of the Iceberg years() transform.
Example fix
// before SELECT years(epoch_millis) FROM t; // after SELECT years(cast(epoch_millis / 1000 as timestamp)) FROM t;
Defensive patterns
Strategy: validation
Validate before calling
if (!(col.dataType() instanceof DateType) && !(col.dataType() instanceof TimestampType) && !(col.dataType() instanceof TimestampNTZType)) { throw new IllegalArgumentException("years() requires date/timestamp: " + col.dataType().catalogString()); } Type guard
boolean isTemporal(DataType t) { return t instanceof DateType || t instanceof TimestampType || t instanceof TimestampNTZType; } Prevention
- Check the column type with DESCRIBE TABLE before using Iceberg transforms.
- Cast epoch/bigint columns to timestamp explicitly.
- Use Spark's built-in year() when you need an int, not a partition transform.
When it happens
Trigger: Calling SELECT years(col) in Spark SQL (or referencing the years() function) where col is not a date or timestamp — e.g. a bigint epoch column, a string 'yyyy-MM-dd', or an int year.
Common situations: Passing an epoch-millis BIGINT column to years() instead of casting to timestamp first; a table column typed as string because source data was ingested untyped; confusion with Spark's built-in year() which accepts date/timestamp only anyway.
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 truncation col to be tinyint, shortint, int, bigint
- 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/5509622b20caa15f.
Report an issue: GitHub.