{"record":{"id":"3d708146f7dc33d0","repo":"apache/iceberg","slug":"unexpected-object-type-for-time-logical-type-rece-3d7081","errorCode":null,"errorMessage":"Unexpected object type for TIME logical type. Received: ","messagePattern":"Unexpected object type for TIME logical type\\. Received: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/formats/avro/AvroToRowDataConverters.java","lineNumber":284,"sourceCode":"      } else {\n        throw new IllegalArgumentException(\n            \"Unexpected object type for DATE logical type. Received: \" + object);\n      }\n    }\n  }\n\n  private static int convertToTime(Object object) {\n    final int millis;\n    if (object instanceof Integer) {\n      millis = (Integer) object;\n    } else if (object instanceof LocalTime) {\n      millis = ((LocalTime) object).get(ChronoField.MILLI_OF_DAY);\n    } else {\n      JodaConverter jodaConverter = JodaConverter.getConverter();\n      if (jodaConverter != null) {\n        millis = jodaConverter.convertTime(object);\n      } else {\n        throw new IllegalArgumentException(\n            \"Unexpected object type for TIME logical type. Received: \" + object);\n      }\n    }\n    return millis;\n  }\n\n  private static byte[] convertToBytes(Object object) {\n    if (object instanceof GenericFixed) {\n      return ((GenericFixed) object).bytes();\n    } else if (object instanceof ByteBuffer) {\n      ByteBuffer byteBuffer = (ByteBuffer) object;\n      byte[] bytes = new byte[byteBuffer.remaining()];\n      byteBuffer.get(bytes);\n      return bytes;\n    } else {\n      return (byte[]) object;\n    }\n  }","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/formats/avro/AvroToRowDataConverters.java#L266-L302","documentation":"convertToTime throws IllegalArgumentException when the object for an Avro TIME logical type is neither java.time.LocalTime (read via MILLI_OF_DAY) nor a Joda-convertible object (with Joda-Time on classpath), so millis-of-day cannot be extracted.","triggerScenarios":"Avro datum for time fields is a java.util.Date, Instant, Long, or other non-LocalTime class; Joda converter null when data holds Joda LocalTime objects.","commonSituations":"Cross-version Avro data where time is encoded as millis long or util.Date; missing joda-time dependency.","solutions":["Ensure the Avro decoder produces java.time.LocalTime for TIME fields","Add joda-time dependency for legacy Joda-encoded data","Pre-convert to millis-of-day before calling the converter"],"exampleFix":"// before\nint millis = convertToTime(legacyDateObject); // throws\n// after\nint millis = convertToTime(LocalTime.ofInstant(legacyDateObject.toInstant(), ZoneOffset.UTC));","handlingStrategy":"type-guard","validationCode":"if (!(object instanceof LocalTime) && !isJodaTime(object)) { throw new IllegalArgumentException(\"Expected LocalTime for TIME field, got \" + object.getClass()); }","typeGuard":"boolean isTimeDatum(Object o) { return o instanceof LocalTime || o instanceof org.joda.time.LocalTime; }","tryCatchPattern":"try { return convertToTime(object); } catch (IllegalArgumentException e) { log.error(\"Bad TIME datum class: {}\", object.getClass()); throw e; }","preventionTips":["Verify the Avro time-millis/time-micros decoder returns LocalTime","Keep joda-time available for legacy data","Run one end-to-end read of representative data before scaling"],"tags":["flink","avro","time","type-mismatch","joda"],"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"}