{"record":{"id":"854871d9885cc409","repo":"apache/beam","slug":"unsupported-iceberg-type-for-beam-type-datetime-valueclass","errorCode":null,"errorMessage":"Unsupported Iceberg type for Beam type DATETIME: {valueClass}","messagePattern":"Unsupported Iceberg type for Beam type DATETIME: (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/IcebergUtils.java","lineNumber":668,"sourceCode":"        break;\n      default:\n        throw new UnsupportedOperationException(\n            \"Unsupported Beam type: \" + field.getType().getTypeName());\n    }\n  }\n\n  private static DateTime getBeamDateTimeValue(Object icebergValue) {\n    long micros;\n    if (icebergValue instanceof OffsetDateTime) {\n      micros = DateTimeUtil.microsFromTimestamptz((OffsetDateTime) icebergValue);\n    } else if (icebergValue instanceof LocalDateTime) {\n      micros = DateTimeUtil.microsFromTimestamp((LocalDateTime) icebergValue);\n    } else if (icebergValue instanceof Long) {\n      micros = (long) icebergValue;\n    } else if (icebergValue instanceof String) {\n      return DateTime.parse((String) icebergValue);\n    } else {\n      throw new UnsupportedOperationException(\n          \"Unsupported Iceberg type for Beam type DATETIME: \" + icebergValue.getClass());\n    }\n    return new DateTime(micros / 1000L);\n  }\n\n  private static Object getLogicalTypeValue(Object icebergValue, Schema.FieldType type) {\n    if (icebergValue instanceof String) {\n      String strValue = (String) icebergValue;\n      if (type.isLogicalType(SqlTypes.DATE.getIdentifier())) {\n        return LocalDate.parse(strValue);\n      } else if (type.isLogicalType(SqlTypes.TIME.getIdentifier())) {\n        return LocalTime.parse(strValue);\n      } else if (type.isLogicalType(SqlTypes.DATETIME.getIdentifier())) {\n        return LocalDateTime.parse(strValue);\n      } else if (type.isLogicalType(Timestamp.IDENTIFIER)) {\n        return OffsetDateTime.parse(strValue).toInstant();\n      }\n    } else if (icebergValue instanceof Long) {","sourceCodeStart":650,"sourceCodeEnd":686,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/IcebergUtils.java#L650-L686","documentation":"getBeamDateTimeValue converts an Iceberg value into a Beam joda DateTime for DATETIME columns. It accepts Iceberg LocalDateTime, Long (micros), and String; any other runtime type throws UnsupportedOperationException, indicating the Iceberg value's class is not a recognized datetime representation.","triggerScenarios":"structToRow/addIcebergValue converts a DATETIME Beam field whose Iceberg value is not LocalDateTime, Long, or String — e.g. java.time.OffsetDateTime from a timestamptz column mapped onto a DATETIME field, an Iceberg Timestamp value object, or a BigDecimal/byte[] from a custom deserializer.","commonSituations":"Mapping a timestamptz Iceberg column to a non-nullable DATETIME Beam field where the reader returned OffsetDateTime; custom Iceberg object models returning different classes; mixing read paths (avro-based vs internal) with different representations.","solutions":["Map timestamptz columns to a Beam field whose value conversion accepts OffsetDateTime, or pre-convert: OffsetDateTime -> LocalDateTime via toLocalDateTime()/toInstant().toEpochMilli()*1000","If you get a java.sql.Timestamp or java.util.Date, convert first: Timestamp.toLocalDateTime() or date.getTime()*1000 for micros","Verify which Iceberg runtime/reader produced the value and normalize at ingestion","Wrap conversion with a small adapter function that normalizes known classes to the accepted three before calling the IO"],"exampleFix":"// before\nObject v = offsetDateTimeValue; // java.time.OffsetDateTime\n// after\nObject v = offsetDateTimeValue.toInstant().toEpochMilli() * 1000L; // micros Long","handlingStrategy":"type-guard","validationCode":"if (!(v instanceof java.time.LocalDateTime) && !(v instanceof Long) && !(v instanceof String)) {\n  throw new IllegalArgumentException(\"DATETIME field value must be LocalDateTime/Long/String, got \" + v.getClass());\n}","typeGuard":"boolean isBeamDatetimeCompatible(Object v) {\n  return v instanceof java.time.LocalDateTime || v instanceof Long || v instanceof String;\n}","tryCatchPattern":"try {\n  row = structToRow(schema, struct);\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage().startsWith(\"Unsupported Iceberg type for Beam type DATETIME\")) {\n    // convert OffsetDateTime/Date to micros and retry\n  } else { throw e; }\n}","preventionTips":["Map timestamptz columns to fields the converter supports, or pre-convert OffsetDateTime to micros","Normalize datetime values at pipeline ingestion","Test read paths against the exact Iceberg reader implementation in use"],"tags":["java","iceberg","beam","type-mismatch","datetime"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}