apache/seatunnel · error · java.lang.IllegalArgumentException

Unable to convert to LocalDate from unexpected value '' of t

Error message

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

What it means

TemporalConversions.toLocalDate converts Debezium/UTC date representations (String, java.util.Date, Long, Integer) into a java.time.LocalDate. When the incoming object is none of the supported types, the method throws this IllegalArgumentException naming the value and its actual class. It signals a mismatch between the source column type and the type the deserializer produced.

Source

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

        }
        if (obj instanceof java.util.Date) {
            java.util.Date date = (java.util.Date) obj;
            return LocalDate.of(date.getYear() + 1900, date.getMonth() + 1, date.getDate());
        }
        if (obj instanceof Long) {
            if ((Long) obj > ChronoField.EPOCH_DAY.range().getMaximum()) {
                return Instant.ofEpochMilli((Long) obj)
                        .atZone(ZoneId.systemDefault())
                        .toLocalDate();
            }
            // Assume the value is the epoch day number
            return LocalDate.ofEpochDay((Long) obj);
        }
        if (obj instanceof Integer) {
            // Assume the value is the epoch day number
            return LocalDate.ofEpochDay((Integer) obj);
        }
        throw new IllegalArgumentException(
                "Unable to convert to LocalDate from unexpected value '"
                        + obj
                        + "' of type "
                        + obj.getClass().getName());
    }

    public static LocalTime toLocalTime(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof LocalTime) {
            return (LocalTime) obj;
        }
        if (obj instanceof LocalDateTime) {
            return ((LocalDateTime) obj).toLocalTime();
        }
        if (obj instanceof java.sql.Date) {
            throw new IllegalArgumentException(

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Inspect the logged class name in the message and add/fix a converter (e.g. a custom SourceTimestampConverter or Debezium converter) so DATE columns are delivered as Integer/Long epoch days or ISO String
  2. Check the Debezium connector's time.precision.mode and 'converters' config; ensure DATE columns map to a supported type
  3. Upgrade or align the connector-cdc-base/Debezium versions so types match what TemporalConversions supports
  4. Pre-convert the value yourself before calling toLocalDate, e.g. unwrap Timestamp or decode micros to epoch days

Example fix

// before
Object value = struct.get("birth_date"); // java.sql.Timestamp
LocalDate d = TemporalConversions.toLocalDate(value, null); // throws
// after
LocalDate d;
if (value instanceof java.sql.Timestamp) {
    d = ((java.sql.Timestamp) value).toLocalDateTime().toLocalDate();
} else {
    d = TemporalConversions.toLocalDate(value, null);
}
Defensive patterns

Strategy: type-guard

Validate before calling

boolean isConvertibleToDate(Object v) {
    return v instanceof String || v instanceof java.util.Date
        || v instanceof Long || v instanceof Integer;
}

Type guard

boolean isEpochDay(Object v) {
    return v instanceof Long || v instanceof Integer;
}

Try / catch

try {
    LocalDate d = TemporalConversions.toLocalDate(value, null);
} catch (IllegalArgumentException e) {
    LOG.warn("Unconvertible DATE value {} ({}), skipping row", value,
        value == null ? "null" : value.getClass().getName(), e);
}

Prevention

When it happens

Trigger: Calling toLocalDate (directly or via localDate) with an object that is not a String, java.util.Date, java.sql.Date, Long, or Integer — e.g. a java.sql.Timestamp, a ByteBuffer/microseconds value, or a custom struct returned by Debezium for a DATE column.

Common situations: CDC reading a DATE column whose converter was not configured (Debezium delivers io.debezium.time.Date as int32 normally, but a schema change or custom SMT yields an unexpected type); using a newer/older Debezium version that changed the emitted type; passing a Timestamp where a date-only value was expected.

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/9e92449914ab0b83. Report an issue: GitHub.