{"record":{"id":"a1665414771b238b","repo":"apache/seatunnel","slug":"unable-to-convert-to-localtime-from-unexpected-val","errorCode":null,"errorMessage":"Unable to convert to LocalTime from unexpected value '' of type ","messagePattern":"Unable to convert to LocalTime from unexpected value '' of type ","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/debezium/utils/TemporalConversions.java","lineNumber":151,"sourceCode":"        }\n        if (obj instanceof Duration) {\n            Long value = ((Duration) obj).toNanos();\n            if (value >= 0 && value <= NANOSECONDS_PER_DAY) {\n                return LocalTime.ofNanoOfDay(value);\n            } else {\n                throw new IllegalArgumentException(\n                        \"Time values must use number of milliseconds greater than 0 and less than 86400000000000\");\n            }\n        }\n        if (obj instanceof String) {\n            // The TIMETZ column is returned as a String which we initially parse here\n            // The parsed offset-time potentially has a zone-offset from the data, shift it after to\n            // GMT.\n            final OffsetTime offsetTime =\n                    OffsetTime.parse((String) obj, TIME_WITH_TIMEZONE_FORMATTER);\n            return offsetTime.toLocalTime();\n        }\n        throw new IllegalArgumentException(\n                \"Unable to convert to LocalTime from unexpected value '\"\n                        + obj\n                        + \"' of type \"\n                        + obj.getClass().getName());\n    }\n\n    @SuppressWarnings(\"MagicNumber\")\n    public static LocalDateTime toLocalDateTime(Object obj, ZoneId serverTimeZone) {\n        if (obj == null) {\n            return null;\n        }\n        if (obj instanceof OffsetDateTime) {\n            return ((OffsetDateTime) obj).toLocalDateTime();\n        }\n        if (obj instanceof Instant) {\n            return ((Instant) obj).atOffset(ZoneOffset.UTC).toLocalDateTime();\n        }\n        if (obj instanceof LocalDateTime) {","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/debezium/utils/TemporalConversions.java#L133-L169","documentation":"toLocalTime supports LocalTime, LocalDateTime, java.sql.Time, Duration, and String (TIMETZ parsed with a timezone formatter). Any other object type reaches the terminal throw, which reports the value and its class. It indicates the deserializer produced a time representation this utility does not recognize.","triggerScenarios":"Calling toLocalTime/localTime with an object of an unsupported class — e.g. java.sql.Timestamp, io.debezium.time.MicroTime as a raw Long, OffsetTime already parsed, or a byte-array/binary representation from a TIME column.","commonSituations":"Debezium emitting io.debezium.time.Time/MicroTime/NanoTime numeric values because no converter was configured; upstream schema changes adding a new wire type; custom SMTs transforming time columns into Timestamp; version drift between connector-cdc-base and the Debezium connector.","solutions":["Inspect the class name in the message; add the corresponding branch or pre-convert (Long micros -> LocalTime.ofNanoOfDay(micros*1000), Timestamp -> toLocalDateTime().toLocalTime())","Configure Debezium time converters so TIME columns are delivered in a supported representation","Align connector-cdc-base and connector-cdc versions (or upgrade SeaTunnel) so all Debezium temporal types are handled","Unwrap Debezium structs before conversion (value without schema: org.apache.kafka.connect.data.Struct -> field value)"],"exampleFix":"// before\nObject v = struct.get(\"start_time\"); // Long micros from Debezium MicroTime\nLocalTime t = TemporalConversions.toLocalTime(v); // throws\n// after\nLocalTime t = (v instanceof Long)\n    ? LocalTime.ofNanoOfDay((Long) v * 1000)\n    : TemporalConversions.toLocalTime(v);","handlingStrategy":"type-guard","validationCode":"boolean isSupportedTimeType(Object v) {\n    return v instanceof LocalTime || v instanceof LocalDateTime\n        || v instanceof java.sql.Time || v instanceof Duration\n        || v instanceof String;\n}","typeGuard":"static LocalTime safeToLocalTime(Object v) {\n    if (v instanceof Long) return LocalTime.ofNanoOfDay((Long) v * 1000);\n    if (v instanceof java.sql.Timestamp) return ((java.sql.Timestamp) v).toLocalDateTime().toLocalTime();\n    return TemporalConversions.toLocalTime(v);\n}","tryCatchPattern":"try {\n    LocalTime t = TemporalConversions.toLocalTime(value);\n} catch (IllegalArgumentException e) {\n    LOG.error(\"Unsupported TIME type {}: {}\", value.getClass(), value, e);\n    throw e;\n}","preventionTips":["Unwrap Kafka Connect Struct fields before calling conversion utilities","Register Debezium converters (converters=...) for TIME/TIMETZ columns","Handle io.debezium.time.MicroTime/NanoTime Long values explicitly","Keep connector-cdc-base and Debezium connector versions aligned"],"tags":["java","cdc","time-conversion","unsupported-type"],"backgroundTag":"unsupported-operation","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}