{"record":{"id":"b8cc9fadab033090","repo":"apache/seatunnel","slug":"unable-to-convert-to-localdatetime-from-unexpected-b8cc9f","errorCode":null,"errorMessage":"Unable to convert to LocalDateTime from unexpected value '${value}' of type ${value.getClass().getName()}","messagePattern":"Unable to convert to LocalDateTime from unexpected value '(.+?)' of type (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-tidb/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/tidb/source/converter/DefaultDataConverter.java","lineNumber":333,"sourceCode":"                    int nanoSecond = instant.getNano();\n                    long millisecond = epochSecond * 1000L + (long) (nanoSecond / 1000000);\n                    int nanoOfMillisecond = nanoSecond % 1000000;\n                    return toLocalDateTime(millisecond, nanoOfMillisecond);\n                }\n                break;\n            case TypeDatetime:\n                if (value instanceof Timestamp) {\n                    LocalDateTime dateTime = ((Timestamp) value).toLocalDateTime();\n                    long epochDay = dateTime.toLocalDate().toEpochDay();\n                    long nanoOfDay = dateTime.toLocalTime().toNanoOfDay();\n                    long millisecond = epochDay * 86400000L + nanoOfDay / 1000000L;\n                    int nanoOfMillisecond = (int) (nanoOfDay % 1000000L);\n\n                    return toLocalDateTime(millisecond, nanoOfMillisecond);\n                }\n                break;\n            default:\n                throw new IllegalArgumentException(\n                        \"Unable to convert to LocalDateTime from unexpected value '\"\n                                + value\n                                + \"' of type \"\n                                + value.getClass().getName());\n        }\n        return value;\n    }\n\n    public static LocalDateTime toLocalDateTime(long millisecond, int nanoOfMillisecond) {\n        // 86400000 = 24 * 60 * 60 * 1000\n        int date = (int) (millisecond / 86400000);\n        int time = (int) (millisecond % 86400000);\n        if (time < 0) {\n            --date;\n            time += 86400000;\n        }\n        long nanoOfDay = time * 1_000_000L + nanoOfMillisecond;\n        LocalDate localDate = LocalDate.ofEpochDay(date);","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-tidb/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/tidb/source/converter/DefaultDataConverter.java#L315-L351","documentation":"convertToTimestamp converts TIMESTAMP columns to LocalDateTime; its switch covers known input types and the default branch rejects any other class with an IllegalArgumentException naming the value and its class name.","triggerScenarios":"A TIMESTAMP column whose runtime value is outside the handled types — e.g. String, byte[], or Integer epoch — falling into the switch's default branch during convert().","commonSituations":"TiDB CDC emitting TIMESTAMP as String after an upgrade; schema drift mapping a non-temporal column to TIMESTAMP; wrapper objects from upstream transforms.","solutions":["Identify the actual runtime class from the message and add a conversion branch for it in convertToTimestamp","Parse Strings with the expected TiDB datetime pattern into LocalDateTime explicitly","Ensure schema types match the real TiDB column types so only temporal classes arrive","Align SeaTunnel connector-cdc-tidb with the TiDB CDC version in use"],"exampleFix":"// before\ndefault:\n    throw new IllegalArgumentException(\"Unable to convert to LocalDateTime...\");\n// after\ncase String:\n    return LocalDateTime.parse(((String) value).replace(' ', 'T'));\ndefault:\n    throw new IllegalArgumentException(\"Unable to convert to LocalDateTime...\");","handlingStrategy":"type-guard","validationCode":"static boolean isLocalDateTimeConvertible(Object v) {\n    return v instanceof LocalDateTime || v instanceof java.sql.Timestamp\n        || v instanceof Long || v instanceof String;\n}","typeGuard":"static LocalDateTime toLdtSafe(Object v) {\n    if (v instanceof LocalDateTime) return (LocalDateTime) v;\n    if (v instanceof java.sql.Timestamp) return ((java.sql.Timestamp) v).toLocalDateTime();\n    if (v instanceof Long) return Instant.ofEpochMilli((Long) v).atZone(ZoneId.systemDefault()).toLocalDateTime();\n    if (v instanceof String) return LocalDateTime.parse(((String) v).replace(' ', 'T'));\n    return null;\n}","tryCatchPattern":"try {\n    return convertToTimestamp(value, dataType);\n} catch (IllegalArgumentException e) {\n    log.error(\"TIMESTAMP conversion failed for {} : {}\", value.getClass(), e.getMessage());\n    throw e;\n}","preventionTips":["Match SeaTunnel schema types to real TiDB column types","Add a String branch if your TiDB CDC version emits datetime strings","Run a sample snapshot test after connector upgrades to catch class changes early"],"tags":["tidb","cdc","timestamp","type-conversion"],"backgroundTag":"type-mismatch","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}