apache/iceberg · error · java.lang.IllegalArgumentException
Unexpected object type for TIME logical type. Received: ${ob
Error message
Unexpected object type for TIME logical type. Received: ${object} What it means
Thrown by AvroToRowDataConverters.convertToTime when an Avro 'time-millis'/'time-micros' logical type field yields an object that is neither java.time.LocalTime nor a Joda-convertible type. The converter needs to extract millis-of-day but cannot from the unexpected object type.
Source
Thrown at flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/formats/avro/AvroToRowDataConverters.java:284
} else {
throw new IllegalArgumentException(
"Unexpected object type for DATE logical type. Received: " + object);
}
}
}
private static int convertToTime(Object object) {
final int millis;
if (object instanceof Integer) {
millis = (Integer) object;
} else if (object instanceof LocalTime) {
millis = ((LocalTime) object).get(ChronoField.MILLI_OF_DAY);
} else {
JodaConverter jodaConverter = JodaConverter.getConverter();
if (jodaConverter != null) {
millis = jodaConverter.convertTime(object);
} else {
throw new IllegalArgumentException(
"Unexpected object type for TIME logical type. Received: " + object);
}
}
return millis;
}
private static byte[] convertToBytes(Object object) {
if (object instanceof GenericFixed) {
return ((GenericFixed) object).bytes();
} else if (object instanceof ByteBuffer) {
ByteBuffer byteBuffer = (ByteBuffer) object;
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
return bytes;
} else {
return (byte[]) object;
}
}View on GitHub (pinned to 86d9c8fc54)
Solutions
- Ensure the Avro schema retains the time logical type and the reader materializes java.time.LocalTime
- Add joda-time dependency if consuming legacy Joda-based records
- Pre-convert the field to LocalTime before the record enters the Avro reader pipeline
- Verify the writer schema logical types match what the reader expects
Example fix
// before: time arrives as Long millis int millis = ((Long) obj).intValue(); // after: convert to LocalTime so the converter accepts it LocalTime t = LocalTime.ofNanoOfDay(((Long) obj) * 1_000_000);
Defensive patterns
Strategy: type-guard
Validate before calling
Object t = record.get("time");
if (!(t instanceof LocalTime)) {
throw new IllegalStateException("Time field must be LocalTime, got: " + t.getClass());
} Type guard
boolean isLocalTime(Object o) {
return o instanceof LocalTime;
} Try / catch
try {
RowData row = converter.convert(record);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Unexpected object type for TIME")) {
// normalize to LocalTime and retry
} else { throw e; }
} Prevention
- Keep time logical types declared in the schema
- Ensure readers materialize java.time.LocalTime
- Include joda-time when bridging legacy Joda data
- Test deserialization of all logical-type fields
When it happens
Trigger: Reading Avro records where a time logical-type field arrives as java.util.Date, String, Long, etc., and JodaConverter is null (joda-time not on the classpath) or cannot handle the type.
Common situations: Legacy Avro writers producing time fields as Joda or util types; java.time-based Flink reads with missing joda-time dependency; schema mismatch dropping the logical type so raw Longs arrive.
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 TIME logical type. Received: ${ob
- Unexpected object type for TIME logical type. Received: " +
- Unexpected object type for TIME logical type. Received:
- Unexpected object type for TIMESTAMP logical type. Received:
- Unexpected object type for DATE logical type. Received: ${ob
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/0f47b8beffb1ffeb.
Report an issue: GitHub.