apache/seatunnel · error · IllegalArgumentException
Unsupported value type for TIMESTAMP_TZ conversion: ${value.
Error message
Unsupported value type for TIMESTAMP_TZ conversion: ${value.getClass().getName()}, value='${value}', TiDB dataType=${dataType} What it means
When convertToOffsetDateTime receives a TIMESTAMP_TZ value whose type is neither OffsetDateTime, LocalDateTime, Timestamp-like, nor String, it throws an IllegalArgumentException describing the class name, value, and TiDB data type, since no conversion path exists.
Source
Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-tidb/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/tidb/source/converter/DefaultDataConverter.java:299
// LocalDateTime without explicit zone — treat as UTC wall-clock value.
return ((LocalDateTime) value).atOffset(ZoneOffset.UTC);
}
if (value instanceof String) {
// String representation from TiDB CDC — attempt ISO-8601 parse.
try {
return OffsetDateTime.parse((String) value);
} catch (java.time.format.DateTimeParseException e) {
throw new IllegalArgumentException(
"Unable to convert TIMESTAMP_TZ from String value: '"
+ value
+ "' for TiDB dataType: "
+ dataType,
e);
}
}
// Unknown type — fail fast with enough context for diagnosis instead of silently
// returning the raw value which would cause a ClassCastException downstream.
throw new IllegalArgumentException(
"Unsupported value type for TIMESTAMP_TZ conversion: "
+ value.getClass().getName()
+ ", value='"
+ value
+ "', TiDB dataType="
+ dataType);
}
private static Object convertToTimestamp(
Object value, org.tikv.common.types.DataType dataType) {
switch (dataType.getType()) {
case TypeTimestamp:
if (value instanceof Timestamp) {
Instant instant = ((Timestamp) value).toInstant();
long epochSecond = instant.getEpochSecond();
int nanoSecond = instant.getNano();
long millisecond = epochSecond * 1000L + (long) (nanoSecond / 1000000);
int nanoOfMillisecond = nanoSecond % 1000000;View on GitHub (pinned to cf67b549a7)
Solutions
- Log/check value.getClass().getName() in the message to identify the actual emitted type
- Add a conversion branch for that type (e.g. epoch millis via Instant.ofEpochMilli(...).atZone(...).toOffsetDateTime())
- Align connector and TiDB CDC plugin versions so expected classes are emitted
- Correct the schema/type mapping so only genuine timestamp values reach TIMESTAMP_TZ conversion
Example fix
// before
throw new IllegalArgumentException("Unsupported value type...");
// after
if (value instanceof Long) {
return Instant.ofEpochMilli((Long) value).atZone(ZoneId.of(timezone)).toOffsetDateTime();
}
throw new IllegalArgumentException("Unsupported value type..."); Defensive patterns
Strategy: type-guard
Validate before calling
static boolean isTimestampConvertible(Object v) {
return v instanceof OffsetDateTime || v instanceof LocalDateTime
|| v instanceof String || v instanceof Long || v instanceof java.util.Date;
} Type guard
static OffsetDateTime toOdtSafe(Object v, ZoneId zone) {
if (v instanceof OffsetDateTime) return (OffsetDateTime) v;
if (v instanceof LocalDateTime) return ((LocalDateTime) v).atZone(zone).toOffsetDateTime();
if (v instanceof Long) return Instant.ofEpochMilli((Long) v).atZone(zone).toOffsetDateTime();
if (v instanceof String) return OffsetDateTime.parse(((String) v).replace(' ', 'T'));
return null;
} Try / catch
try {
return convertToOffsetDateTime(value, dataType);
} catch (IllegalArgumentException e) {
// message already includes class name; route to DLQ or rethrow
throw e;
} Prevention
- Log unexpected classes at the boundary and add converter branches for them
- Verify schema type mapping so only temporal values reach TIMESTAMP_TZ conversion
- Keep connector and TiDB CDC plugin versions aligned
When it happens
Trigger: convert() passes an unexpected object for a TIMESTAMP_TZ column — e.g. Long epoch millis, java.util.Date, or byte[] — after the String/known-type branches did not match.
Common situations: TiDB CDC version change altering emitted classes; schema mismatched so an INT/epoch column mapped to TIMESTAMP_TZ; upstream transform wrapping values.
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
- Unsupported BYTES value type: ${value.getClass().getSimpleNa
- Unable to convert TIMESTAMP_TZ from String value: '${value}'
- Unable to convert to LocalDateTime from unexpected value '${
- Unsupported type %s for numeric plus.
- Unsupported type %s for numeric minus.
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/33426f7f3254b25a.
Report an issue: GitHub.