{"record":{"id":"990d9587fb755c40","repo":"apache/iceberg","slug":"expected-value-to-be-date-or-timestamp-valuetyp-990d95","errorCode":null,"errorMessage":"Expected value to be date or timestamp: ${valueType.catalogString()}","messagePattern":"Expected value to be date or timestamp: (.+?)","errorType":"exception","errorClass":"java.lang.UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/functions/DaysFunction.java","lineNumber":48,"sourceCode":"import org.apache.spark.sql.types.TimestampType;\n\n/**\n * A Spark function implementation for the Iceberg day transform.\n *\n * <p>Example usage: {@code SELECT system.days('source_col')}.\n */\npublic class DaysFunction extends UnaryUnboundFunction {\n\n  @Override\n  protected BoundFunction doBind(DataType valueType) {\n    if (valueType instanceof DateType) {\n      return new DateToDaysFunction();\n    } else if (valueType instanceof TimestampType) {\n      return new TimestampToDaysFunction();\n    } else if (valueType instanceof TimestampNTZType) {\n      return new TimestampNtzToDaysFunction();\n    } else {\n      throw new UnsupportedOperationException(\n          \"Expected value to be date or timestamp: \" + valueType.catalogString());\n    }\n  }\n\n  @Override\n  public String description() {\n    return name()\n        + \"(col) - Call Iceberg's day transform\\n\"\n        + \"  col :: source column (must be date or timestamp)\";\n  }\n\n  @Override\n  public String name() {\n    return \"days\";\n  }\n\n  protected abstract static class BaseToDaysFunction extends BaseScalarFunction<Integer>\n      implements ReducibleFunction<Integer, Integer> {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/functions/DaysFunction.java#L30-L66","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Cast the column first: days(CAST(ts_str AS TIMESTAMP)).","Use to_date/to_timestamp to convert string dates before applying days().","If the value is an epoch number, convert to timestamp, e.g. days(timestamp_millis(epoch_col)).","Fix the table schema/column type if the partition spec was intended for a temporal column."],"exampleFix":"// before\nSELECT days(ts_str) FROM t  -- ts_str is STRING\n// after\nSELECT days(CAST(ts_str AS TIMESTAMP)) FROM t","handlingStrategy":"validation","validationCode":"// Spark Scala\nval dt = df.schema(\"value_col\").dataType\nrequire(dt == org.apache.spark.sql.types.DateType || dt.typeName.startsWith(\"timestamp\"),\n  s\"days() requires DATE or TIMESTAMP, got: ${dt.catalogString}\")","typeGuard":"def isTemporalType(dt: org.apache.spark.sql.types.DataType): Boolean =\n  dt == org.apache.spark.sql.types.DateType ||\n  dt.isInstanceOf[org.apache.spark.sql.types.TimestampType] ||\n  dt.typeName == \"timestamp_ntz\"","tryCatchPattern":"try {\n  df.select(expr(\"days(ts_col)\"))\n} catch {\n  case e: UnsupportedOperationException if e.getMessage.startsWith(\"Expected value to be date or timestamp\") =>\n    throw new IllegalArgumentException(\"days() needs a DATE/TIMESTAMP column; cast or use to_date/to_timestamp\", e)\n}","preventionTips":["Check the column type with printSchema/DESCRIBE TABLE before temporal transforms","Parse string dates with to_date/to_timestamp before days()","Never pass epoch numeric columns directly — convert with timestamp_millis()","In partition specs, ensure the partitioned column is DATE or TIMESTAMP"],"tags":["spark","sql-function","type-mismatch","temporal"],"backgroundTag":"type-mismatch","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}