apache/iceberg · error · java.lang.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 days(x) Spark transform function only accepts date, timestamp, or timestamp_ntz inputs. Binding any other value type (numeric, string, etc.) fails with this UnsupportedOperationException, appending the offending type's catalogString to the message. Thrown during query analysis via doBind.

Source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/functions/DaysFunction.java:48

import org.apache.spark.sql.types.TimestampType;

/**
 * A Spark function implementation for the Iceberg day transform.
 *
 * <p>Example usage: {@code SELECT system.days('source_col')}.
 */
public class DaysFunction extends UnaryUnboundFunction {

  @Override
  protected BoundFunction doBind(DataType valueType) {
    if (valueType instanceof DateType) {
      return new DateToDaysFunction();
    } else if (valueType instanceof TimestampType) {
      return new TimestampToDaysFunction();
    } else if (valueType instanceof TimestampNTZType) {
      return new TimestampNtzToDaysFunction();
    } else {
      throw new UnsupportedOperationException(
          "Expected value to be date or timestamp: " + valueType.catalogString());
    }
  }

  @Override
  public String description() {
    return name()
        + "(col) - Call Iceberg's day transform\n"
        + "  col :: source column (must be date or timestamp)";
  }

  @Override
  public String name() {
    return "days";
  }

  protected abstract static class BaseToDaysFunction extends BaseScalarFunction<Integer>
      implements ReducibleFunction<Integer, Integer> {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Cast the column first: days(CAST(ts_str AS TIMESTAMP)).
  2. Use to_date/to_timestamp to convert string dates before applying days().
  3. If the value is an epoch number, convert to timestamp, e.g. days(timestamp_millis(epoch_col)).
  4. Fix the table schema/column type if the partition spec was intended for a temporal column.

Example fix

// before
SELECT days(ts_str) FROM t  -- ts_str is STRING
// after
SELECT days(CAST(ts_str AS TIMESTAMP)) FROM t
Defensive patterns

Strategy: validation

Validate before calling

// Spark Scala
val dt = df.schema("value_col").dataType
require(dt == org.apache.spark.sql.types.DateType || dt.typeName.startsWith("timestamp"),
  s"days() requires DATE or TIMESTAMP, got: ${dt.catalogString}")

Type guard

def isTemporalType(dt: org.apache.spark.sql.types.DataType): Boolean =
  dt == org.apache.spark.sql.types.DateType ||
  dt.isInstanceOf[org.apache.spark.sql.types.TimestampType] ||
  dt.typeName == "timestamp_ntz"

Try / catch

try {
  df.select(expr("days(ts_col)"))
} catch {
  case e: UnsupportedOperationException if e.getMessage.startsWith("Expected value to be date or timestamp") =>
    throw new IllegalArgumentException("days() needs a DATE/TIMESTAMP column; cast or use to_date/to_timestamp", e)
}

Prevention

When it happens

Trigger: Calling days(value) where value is a StringType (e.g. a date stored as string), a LongType epoch, or any non-temporal column, e.g. days('2024-01-01') or days(ts_str).

Common situations: Dates stored as strings in a column being partitioned by days(); passing an epoch bigint; using days() in a CREATE TABLE partition spec on a string column.

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/990d9587fb755c40. Report an issue: GitHub.