apache/seatunnel · error · java.lang.IllegalArgumentException
Unable to convert to LocalTime from unexpected value '' of t
Error message
Unable to convert to LocalTime from unexpected value '' of type
What it means
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.
Source
Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/debezium/utils/TemporalConversions.java:151
}
if (obj instanceof Duration) {
Long value = ((Duration) obj).toNanos();
if (value >= 0 && value <= NANOSECONDS_PER_DAY) {
return LocalTime.ofNanoOfDay(value);
} else {
throw new IllegalArgumentException(
"Time values must use number of milliseconds greater than 0 and less than 86400000000000");
}
}
if (obj instanceof String) {
// The TIMETZ column is returned as a String which we initially parse here
// The parsed offset-time potentially has a zone-offset from the data, shift it after to
// GMT.
final OffsetTime offsetTime =
OffsetTime.parse((String) obj, TIME_WITH_TIMEZONE_FORMATTER);
return offsetTime.toLocalTime();
}
throw new IllegalArgumentException(
"Unable to convert to LocalTime from unexpected value '"
+ obj
+ "' of type "
+ obj.getClass().getName());
}
@SuppressWarnings("MagicNumber")
public static LocalDateTime toLocalDateTime(Object obj, ZoneId serverTimeZone) {
if (obj == null) {
return null;
}
if (obj instanceof OffsetDateTime) {
return ((OffsetDateTime) obj).toLocalDateTime();
}
if (obj instanceof Instant) {
return ((Instant) obj).atOffset(ZoneOffset.UTC).toLocalDateTime();
}
if (obj instanceof LocalDateTime) {View on GitHub (pinned to cf67b549a7)
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)
Example fix
// before
Object v = struct.get("start_time"); // Long micros from Debezium MicroTime
LocalTime t = TemporalConversions.toLocalTime(v); // throws
// after
LocalTime t = (v instanceof Long)
? LocalTime.ofNanoOfDay((Long) v * 1000)
: TemporalConversions.toLocalTime(v); Defensive patterns
Strategy: type-guard
Validate before calling
boolean isSupportedTimeType(Object v) {
return v instanceof LocalTime || v instanceof LocalDateTime
|| v instanceof java.sql.Time || v instanceof Duration
|| v instanceof String;
} Type guard
static LocalTime safeToLocalTime(Object v) {
if (v instanceof Long) return LocalTime.ofNanoOfDay((Long) v * 1000);
if (v instanceof java.sql.Timestamp) return ((java.sql.Timestamp) v).toLocalDateTime().toLocalTime();
return TemporalConversions.toLocalTime(v);
} Try / catch
try {
LocalTime t = TemporalConversions.toLocalTime(value);
} catch (IllegalArgumentException e) {
LOG.error("Unsupported TIME type {}: {}", value.getClass(), value, e);
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Unable to convert to LocalDate from a java.sql.Date value '
- Time values must use number of milliseconds greater than 0 a
- Unsupported type %s for numeric plus.
- Unsupported type %s for numeric minus.
- Unsupported type:
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/a1665414771b238b.
Report an issue: GitHub.