apache/seatunnel · error · java.lang.IllegalArgumentException

Unable to parse OffsetDateTime from CDC TIMESTAMP_TZ value:

Error message

Unable to parse OffsetDateTime from CDC TIMESTAMP_TZ value: ''. Supported formats: ISO-8601 with numeric offset, IANA zone-region id, space-separated date/time, short-form hour-only offset, UTC epoch literal.

What it means

parseOffsetDateTimeFromString() converts a CDC TIMESTAMP_TZ string value to an OffsetDateTime. It tries multiple formats: ISO-8601 with offset, IANA region id, space-separated datetime, short hour-only offset, and Instant/epoch literal. When the string matches none, it throws IllegalArgumentException listing all supported formats.

Source

Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/debezium/row/SeaTunnelRowDebeziumDeserializationConverters.java:514

            // fall through
        }

        // 3. Space separator or short offset: 2024-01-01 12:00:00+08:00 / +08
        try {
            return java.time.OffsetDateTime.parse(str, FLEXIBLE_OFFSET_FORMATTER)
                    .withOffsetSameInstant(java.time.ZoneOffset.UTC);
        } catch (java.time.format.DateTimeParseException ignored) {
            // fall through
        }

        // 4. UTC epoch literal: 2024-01-01T12:00:00Z
        try {
            return Instant.parse(str).atOffset(java.time.ZoneOffset.UTC);
        } catch (java.time.format.DateTimeParseException ignored) {
            // fall through
        }

        throw new IllegalArgumentException(
                "Unable to parse OffsetDateTime from CDC TIMESTAMP_TZ value: '"
                        + str
                        + "'. Supported formats: ISO-8601 with numeric offset, IANA zone-region"
                        + " id, space-separated date/time, short-form hour-only offset, UTC"
                        + " epoch literal.");
    }

    private static DebeziumDeserializationConverter convertToTimestamp(ZoneId serverTimeZone) {
        return new DebeziumDeserializationConverter() {
            private static final long serialVersionUID = 1L;

            @SuppressWarnings("MagicNumber")
            @Override
            public Object convert(Object dbzObj, Schema schema) {
                if (dbzObj instanceof Long) {
                    switch (schema.name()) {
                        case Timestamp.SCHEMA_NAME:
                            return toLocalDateTime((Long) dbzObj, 0);

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Fix the source data: replace empty/zero-date timestamp values with valid timestamps (e.g. NULL or a sentinel like '1970-01-01T00:00:00Z').
  2. Ensure the column produces ISO-8601 or IANA-zone formatted values; add a converter/transform to normalize before deserialization.
  3. Check the exact offending value in the message; if it is a legitimate new format, extend the parser chain in SeaTunnelRowDebeziumDeserializationConverters.

Example fix

// before
// source contains '' or '0000-00-00 00:00:00' for TIMESTAMP_TZ
// after
UPDATE t SET ts = NULL WHERE ts = '0000-00-00 00:00:00';
// or configure the job to map invalid dates to null/sentinel
Defensive patterns

Strategy: validation

Validate before calling

// Java: pre-validate CDC timestamp strings
static boolean isParsableTimestampTz(String s) {
    if (s == null || s.isEmpty()) return false;
    try { OffsetDateTime.parse(s); return true; } catch (Exception ignored) {}
    try { ZoneId.of(s); return true; } catch (Exception ignored) {}
    try { Instant.parse(s); return true; } catch (Exception ignored) {}
    return s.matches("[+-]\\d{2}(:?\\d{2})?") || s.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}(:\\d{2})?");
}

Type guard

if (v == null || (v instanceof String && ((String) v).trim().isEmpty())) {
    return null; // treat empty TIMESTAMP_TZ as null before parsing
}

Try / catch

try {
    odt = parseOffsetDateTimeFromString(str);
} catch (IllegalArgumentException e) {
    log.warn("unparseable TIMESTAMP_TZ '{}', substituting null/sentinel", str);
    odt = null;
}

Prevention

When it happens

Trigger: A TIMESTAMP_TZ CDC value that is empty, null-rendered as '', or formatted in a non-ISO layout (e.g. custom driver string or locale-dependent text) reaches convert() -> parseOffsetDateTimeFromString().

Common situations: Empty string timestamps from some database drivers or placeholder values (e.g. '0000-00-00 00:00:00' style zero dates from MySQL), or a date-time format not covered by the parser branches.

Understand the failure class

Related errors


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