{"record":{"id":"02bcf91725346304","repo":"apache/iceberg","slug":"expected-value-to-be-date-or-timestamp-02bcf9","errorCode":null,"errorMessage":"Expected value to be date or timestamp: ","messagePattern":"Expected value to be date or timestamp: ","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/functions/YearsFunction.java","lineNumber":46,"sourceCode":"import org.apache.spark.sql.types.TimestampType;\n\n/**\n * A Spark function implementation for the Iceberg year transform.\n *\n * <p>Example usage: {@code SELECT system.years('source_col')}.\n */\npublic class YearsFunction extends UnaryUnboundFunction {\n\n  @Override\n  protected BoundFunction doBind(DataType valueType) {\n    if (valueType instanceof DateType) {\n      return new DateToYearsFunction();\n    } else if (valueType instanceof TimestampType) {\n      return new TimestampToYearsFunction();\n    } else if (valueType instanceof TimestampNTZType) {\n      return new TimestampNtzToYearsFunction();\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 year transform\\n\"\n        + \"  col :: source column (must be date or timestamp)\";\n  }\n\n  @Override\n  public String name() {\n    return \"years\";\n  }\n\n  private abstract static class BaseToYearsFunction extends BaseScalarFunction<Integer> {\n    @Override","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/functions/YearsFunction.java#L28-L64","documentation":"YearsFunction binds Iceberg's years() transform, which only accepts DATE, TIMESTAMP, or TIMESTAMP_NTZ values. doBind() throws this UnsupportedOperationException (appending the offending type's catalog string) for any other input type.","triggerScenarios":"Calling years() with a string ('2023-01-01'), bigint epoch, int, or date-formatted column without casting to DATE/TIMESTAMP first.","commonSituations":"Passing raw string dates read from CSV/JSON sources; passing unix-epoch BIGINT columns expecting years() to interpret them; using years() on DATE values written as strings in views.","solutions":["Cast the input: years(CAST(col AS TIMESTAMP)) or years(CAST(col AS DATE))","If the value is a string in a known format, use to_date/to_timestamp first: years(to_timestamp(col))","If the value is an epoch number, convert with timestamp_seconds(col) before calling years()"],"exampleFix":"// before\nSELECT years(event_date_str) FROM t;\n// after\nSELECT years(to_date(event_date_str)) FROM t;","handlingStrategy":"validation","validationCode":"require(Seq(\"date\",\"timestamp\",\"timestamp_ntz\").contains(valueCol.dataType.simpleString), s\"years() needs date/timestamp, got ${valueCol.dataType}\")","typeGuard":"def isTemporal(t: DataType): Boolean = t match { case _: DateType | _: TimestampType | _: TimestampNTZType => true; case _ => false }","tryCatchPattern":"try { ... } catch { case e: UnsupportedOperationException if e.getMessage.startsWith(\"Expected value to be date or timestamp\") => ... }","preventionTips":["Cast string dates with to_date/to_timestamp before years()","Convert epoch numbers with timestamp_seconds()","Infer schema explicitly when reading CSV/JSON so dates are typed, not strings"],"tags":["spark","sql","type-mismatch","function-binding"],"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"}