apache/seatunnel · error · java.lang.IllegalArgumentException

Unable to convert to LocalDateTime from unexpected value ''

Error message

Unable to convert to LocalDateTime from unexpected value '' of type 

What it means

toLocalDateTime converts timestamp-like values into java.time.LocalDateTime, supporting Long (epoch millis/micros depending on overload), java.util.Date, java.sql.Timestamp, LocalDateTime, and ISO-8601 Instant strings parsed against the server time zone. When the object matches none of these, the method throws this IllegalArgumentException naming the value and its class. It means the TIMESTAMP column's wire representation is not what the converter expects.

Source

Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/debezium/utils/TemporalConversions.java:222

                millis = MILLISECONDS_PER_SECOND + millis;
            }
            int nanosOfSecond = (int) (millis * NANOSECONDS_PER_MILLISECOND);
            return LocalDateTime.of(
                    date.getYear() + 1900,
                    date.getMonth() + 1,
                    date.getDate(),
                    date.getHours(),
                    date.getMinutes(),
                    date.getSeconds(),
                    nanosOfSecond);
        }
        if (obj instanceof String) {
            String str = (String) obj;
            // TIMESTAMP type is encoded in string type
            Instant instant = Instant.parse(str);
            return LocalDateTime.ofInstant(instant, serverTimeZone);
        }
        throw new IllegalArgumentException(
                "Unable to convert to LocalDateTime from unexpected value '"
                        + obj
                        + "' of type "
                        + obj.getClass().getName());
    }
}

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Log/inspect the class in the message and pre-normalize the value (e.g. reformat 'yyyy-MM-dd HH:mm:ss' strings to ISO-8601 with 'T' before calling, or use the correct Long overload for micros vs millis)
  2. Check the toLocalDateTime overload used: pass the right TimeUnit/ZoneId so Debezium micros-based timestamps are converted correctly
  3. Configure Debezium time converters (io.debezium.converters.*) so TIMESTAMP columns arrive as a supported type
  4. Align connector-cdc-base version with the Debezium connector version in use

Example fix

// before
String raw = "2024-01-15 10:30:00"; // not ISO, Instant.parse would also fail
LocalDateTime dt = TemporalConversions.toLocalDateTime(raw, zoneId); // throws
// after
String iso = raw.replace(' ', 'T') + (raw.length() <= 10 ? "T00:00:00" : "");
LocalDateTime dt = TemporalConversions.toLocalDateTime(iso, zoneId);
Defensive patterns

Strategy: type-guard

Validate before calling

boolean isConvertibleToDateTime(Object v) {
    if (v instanceof String) {
        try { java.time.Instant.parse((String) v); return true; }
        catch (Exception e) { return false; }
    }
    return v instanceof Long || v instanceof java.util.Date
        || v instanceof java.sql.Timestamp || v instanceof LocalDateTime;
}

Type guard

boolean isIsoInstantString(Object v) {
    return v instanceof String
        && ((String) v).matches("\\d{4}-\\d{2}-\\d{2}T.*Z?.*");
}

Try / catch

try {
    LocalDateTime dt = TemporalConversions.toLocalDateTime(value, zoneId);
} catch (IllegalArgumentException e) {
    LOG.warn("Unconvertible TIMESTAMP value {} ({}), using null", value,
        value == null ? "null" : value.getClass().getName());
    return null;
}

Prevention

When it happens

Trigger: Calling toLocalDateTime with an unsupported object — e.g. a java.sql.Date, a BigDecimal from high-precision DECIMAL-encoded timestamps, a Debezium Struct field left unwrapped, or a non-ISO String (e.g. 'yyyy-MM-dd HH:mm:ss' without 'T'/offset) that fails Instant.parse before the typed branches.

Common situations: Source database TIMESTAMP stored/replicated in a non-ISO string format; MySQL/Postgres CDC delivering microseconds (io.debezium.time.MicroTimestamp) while code calls the millis overload; timezone misconfiguration producing unexpected types; schema evolution changing the column representation.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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