apache/iceberg · error · UnsupportedOperationException
Expected value to be timestamp
Error message
Expected value to be timestamp: ${valueType.catalogString()} What it means
Iceberg's hours() transform function binds its single argument at planning time. Only TIMESTAMP and TIMESTAMP_NTZ have a defined hour-granularity transform (hour is meaningless for bare DATE), so any other type — including DATE — throws UnsupportedOperationException with the actual type name.
Solutions
- Cast a DATE column to TIMESTAMP if hour info is meaningful: hours(cast(d AS TIMESTAMP)).
- Cast a string timestamp: hours(cast(ts_str AS TIMESTAMP)).
- Convert epoch millis: hours(timestamp_millis(epoch_ms_col)).
- If the column is truly date-only, use iceberg.days(d) instead.
Example fix
// before SELECT iceberg.hours(event_date) FROM t; -- DATE // after SELECT iceberg.hours(CAST(event_date AS TIMESTAMP)) FROM t;
Defensive patterns
Strategy: type-guard
Validate before calling
require(col.dataType == TimestampType || col.dataType == TimestampNTZType,
s"hours() requires timestamp, got ${col.dataType}") Type guard
def isTimestampLike(t: DataType): Boolean = t == TimestampType || t == TimestampNTZType
Prevention
- Use iceberg.days() instead of hours() for DATE columns
- Never persist event time as VARCHAR if hour-level partitioning is planned
When it happens
Trigger: Calling iceberg.hours(col) where col is DATE, STRING, INT, BIGINT or anything other than timestamp/timestamp_ntz — e.g. hours(d) where d is a DATE column.
Common situations: Applying hours() to a date-only column; passing a string timestamp; passing epoch milliseconds BIGINT from event logs.
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 column to be date, tinyint, smallint, int, bigint…
- Expected truncation col to be tinyint, shortint, int…
- Expected value to be date or timestamp
- Expected value to be date or timestamp
- Cannot bind: does not accept arguments
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/4cc067c34cf98fa1.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/functions/HoursFunction.java:46
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.TimestampNTZType;
import org.apache.spark.sql.types.TimestampType;
/**
* A Spark function implementation for the Iceberg hour transform.
*
* <p>Example usage: {@code SELECT system.hours('source_col')}.
*/
public class HoursFunction extends UnaryUnboundFunction {
@Override
protected BoundFunction doBind(DataType valueType) {
if (valueType instanceof TimestampType) {
return new TimestampToHoursFunction();
} else if (valueType instanceof TimestampNTZType) {
return new TimestampNtzToHoursFunction();
} else {
throw new UnsupportedOperationException(
"Expected value to be timestamp: " + valueType.catalogString());
}
}
@Override
public String description() {
return name()
+ "(col) - Call Iceberg's hour transform\n"
+ " col :: source column (must be timestamp)";
}
@Override
public String name() {
return "hours";
}
public abstract static class BaseToHourFunction extends BaseScalarFunction<Integer>
implements ReducibleFunction<Integer, Integer> {View on GitHub (pinned to 86d9c8fc54)