apache/iceberg · error · java.lang.IllegalArgumentException
Unexpected object type for TIMESTAMP logical type. Received:
Error message
Unexpected object type for TIMESTAMP logical type. Received: ${object} What it means
Thrown by AvroToRowDataConverters.convertToTimestamp when an Avro 'timestamp-millis'/'timestamp-micros' logical type field yields an object that is neither java.time.LocalDateTime nor a type supported by the Joda converter. The converter cannot map the runtime object to Flink TimestampData, so it fails fast with the offending object in the message.
Source
Thrown at flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/formats/avro/AvroToRowDataConverters.java:251
return TimestampData.fromEpochMillis(timeLong);
} else if (precision <= 6) {
return TimestampData.fromEpochMillis(
Math.floorDiv(timeLong, 1000L), (int) Math.floorMod(timeLong, 1000L) * 1000);
} else {
// Iceberg: Added support for nanoseconds precision (FLINK-39251)
return TimestampData.fromEpochMillis(
Math.floorDiv(timeLong, 1_000_000L), (int) Math.floorMod(timeLong, 1_000_000L));
}
} else if (object instanceof Instant) {
return TimestampData.fromInstant((Instant) object);
} else if (object instanceof LocalDateTime) {
return TimestampData.fromLocalDateTime((LocalDateTime) object);
} else {
JodaConverter jodaConverter = JodaConverter.getConverter();
if (jodaConverter != null) {
return TimestampData.fromEpochMillis(jodaConverter.convertTimestamp(object));
} else {
throw new IllegalArgumentException(
"Unexpected object type for TIMESTAMP logical type. Received: " + object);
}
}
}
private static int convertToDate(Object object) {
if (object instanceof Integer) {
return (Integer) object;
} else if (object instanceof LocalDate) {
return (int) ((LocalDate) object).toEpochDay();
} else {
JodaConverter jodaConverter = JodaConverter.getConverter();
if (jodaConverter != null) {
return (int) jodaConverter.convertDate(object);
} else {
throw new IllegalArgumentException(
"Unexpected object type for DATE logical type. Received: " + object);
}View on GitHub (pinned to 86d9c8fc54)
Solutions
- Add the joda-time dependency so JodaConverter can convert legacy objects, or re-register the Avro reader schema with a java.time-compatible value class
- Ensure the Avro specific/reflect record maps timestamp logical types to LocalDateTime (configure the reflect data model to use java.time)
- Convert the field yourself with a custom DatumReader/Conversion so the object reaching the converter is LocalDateTime
- Check the reader schema matches the writer schema's logical types
Example fix
// before (joda-time missing, legacy data)
Object obj = record.get("ts"); // java.util.Date
// after: add joda-time to the classpath or convert first
TimestampData ts = TimestampData.fromLocalDateTime(
LocalDateTime.ofInstant(((java.util.Date) obj).toInstant(), ZoneOffset.UTC)); Defensive patterns
Strategy: type-guard
Validate before calling
Object ts = record.get("ts");
if (!(ts instanceof LocalDateTime) && !(ts instanceof java.util.Date) && !(ts instanceof Long)) {
throw new IllegalStateException("Unexpected timestamp type: " + ts.getClass());
} Type guard
boolean isSupportedTimestamp(Object o) {
return o instanceof LocalDateTime || o instanceof java.util.Date || o instanceof Long;
} Try / catch
try {
RowData row = converter.convert(record);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Unexpected object type for TIMESTAMP")) {
// normalize the object and retry
} else { throw e; }
} Prevention
- Keep joda-time on the classpath when consuming legacy Avro data
- Align reader/writer Avro schemas and logical type conversions
- Prefer specific records generated with java.time mappings
- Validate sample records' runtime types before running full jobs
When it happens
Trigger: Reading Avro data whose timestamp field deserialized to an unexpected type (e.g. java.util.Date, Long, org.joda.time.DateTime when Joda classes are absent from the classpath so JodaConverter.getConverter() returns null).
Common situations: Avro files written by frameworks that materialize timestamps as java.util.Date or epoch Long; running Flink 1.9+ (java.time default mapping) against records produced with the legacy Joda mapping without joda-time on the classpath.
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
- Unexpected object type for TIMESTAMP logical type. Received:
- Unexpected object type for TIMESTAMP logical type. Received:
- Unexpected object type for TIMESTAMP logical type. Received:
- Unknown type for long field. Type name: ${className}
- Unknown type for timestamp_ns: ${class}
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/401b06147afd8a66.
Report an issue: GitHub.