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
- 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
- Check the Debezium connector's time.precision.mode and 'converters' config; ensure DATE columns map to a supported type
- Upgrade or align the connector-cdc-base/Debezium versions so types match what TemporalConversions supports
- 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
- Log value.getClass().getName() before conversion in new connectors
- Register Debezium time converters in the connector config
- Pin compatible SeaTunnel connector-cdc and Debezium versions
- Unit-test conversions against the actual wire types your source emits
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
- Unable to convert to LocalDate from a java.sql.Date value '
- Unable to convert to LocalDateTime from unexpected value ''
- Sparse vector value must be a Number, but got: %s
- Unsupported timestamp type:
- Value is not a BSON date or timestamp
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/9e92449914ab0b83.
Report an issue: GitHub.