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
Iceberg's `years` function binds only when the value is a date, timestamp, or timestamp_ntz. `doBind` in YearsFunction throws this UnsupportedOperationException, including the actual type via `catalogString()`, when given any other type, since converting to years-since-epoch is only defined for temporal types.
Source
Thrown at spark/v3.5/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 to a temporal type: `years(CAST(epoch_col AS TIMESTAMP))` or `years(to_date(str_col))`.
- For epoch values, use timestamp_seconds first: `years(timestamp_seconds(epoch_col))`.
- Verify the column type with DESCRIBE TABLE and fix the upstream schema.
Example fix
// before
spark.sql("SELECT years(ts_str) FROM t")
// after
spark.sql("SELECT years(CAST(ts_str AS TIMESTAMP)) FROM t") Defensive patterns
Strategy: type-guard
Validate before calling
DataType dt = df.schema().apply("col").dataType();
if (!(dt instanceof DateType || dt instanceof TimestampType || dt instanceof TimestampNTZType)) throw new IllegalArgumentException("years() requires a temporal column, got: " + dt.simpleString()); Type guard
boolean isTemporal(DataType dt) { return dt instanceof DateType || dt instanceof TimestampType || dt instanceof TimestampNTZType; } Try / catch
try { spark.sql("SELECT years(col) FROM t"); } catch (UnsupportedOperationException e) { if (e.getMessage().startsWith("Expected value to be date or timestamp")) { /* cast col to DATE/TIMESTAMP */ } throw e; } Prevention
- CAST string/epoch columns to DATE/TIMESTAMP before applying temporal functions.
- Use timestamp_seconds() for epoch bigint columns.
- Verify column types with DESCRIBE TABLE after schema changes.
When it happens
Trigger: Calling `years(col)` where col is int, bigint, string, decimal, etc., instead of DATE/TIMESTAMP/TIMESTAMP_NTZ.
Common situations: Passing epoch integers expecting conversion; passing string dates without CAST; schema evolution changed a column from date to string.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Expected value to be date or timestamp: ${valueType.catalogS
- Expected value to be timestamp: ${valueType.catalogString()}
- Expected value to be date or timestamp: ${valueType.catalogS
- Expected value to be date or timestamp: ${valueType.catalogS
- Expected value to be timestamp: ${valueType.catalogString()}
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/8f8f9a118680aebf.
Report an issue: GitHub.