apache/seatunnel · error · java.lang.IllegalArgumentException

Unable to convert to LocalTime from unexpected value '' of…

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.

Solutions

  1. Inspect the class name in the message; add the corresponding branch or pre-convert (Long micros -> LocalTime.ofNanoOfDay(micros*1000), Timestamp -> toLocalDateTime().toLocalTime())
  2. Configure Debezium time converters so TIME columns are delivered in a supported representation
  3. Align connector-cdc-base and connector-cdc versions (or upgrade SeaTunnel) so all Debezium temporal types are handled
  4. 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

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


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/a1665414771b238b. Report an issue: GitHub.

Appendix: 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)