{"record":{"id":"5865676c8e273e7b","repo":"apache/seatunnel","slug":"time-values-must-use-number-of-milliseconds-greate-586567","errorCode":null,"errorMessage":"Time values must use number of milliseconds greater than 0 and less than 86400000000000","messagePattern":"Time values must use number of milliseconds greater than 0 and less than 86400000000000","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/debezium/utils/TemporalConversions.java","lineNumber":139,"sourceCode":"            return LocalTime.of(\n                    timestamp.getHours(),\n                    timestamp.getMinutes(),\n                    timestamp.getSeconds(),\n                    timestamp.getNanos());\n        }\n        if (obj instanceof java.util.Date) {\n            java.util.Date date = (java.util.Date) obj;\n            long millis = (int) (date.getTime() % MILLISECONDS_PER_SECOND);\n            int nanosOfSecond = (int) (millis * NANOSECONDS_PER_MILLISECOND);\n            return LocalTime.of(\n                    date.getHours(), date.getMinutes(), date.getSeconds(), nanosOfSecond);\n        }\n        if (obj instanceof Duration) {\n            Long value = ((Duration) obj).toNanos();\n            if (value >= 0 && value <= NANOSECONDS_PER_DAY) {\n                return LocalTime.ofNanoOfDay(value);\n            } else {\n                throw new IllegalArgumentException(\n                        \"Time values must use number of milliseconds greater than 0 and less than 86400000000000\");\n            }\n        }\n        if (obj instanceof String) {\n            // The TIMETZ column is returned as a String which we initially parse here\n            // The parsed offset-time potentially has a zone-offset from the data, shift it after to\n            // GMT.\n            final OffsetTime offsetTime =\n                    OffsetTime.parse((String) obj, TIME_WITH_TIMEZONE_FORMATTER);\n            return offsetTime.toLocalTime();\n        }\n        throw new IllegalArgumentException(\n                \"Unable to convert to LocalTime from unexpected value '\"\n                        + obj\n                        + \"' of type \"\n                        + obj.getClass().getName());\n    }\n","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/debezium/utils/TemporalConversions.java#L121-L157","documentation":"toLocalTime converts a java.time.Duration (Debezium's io.debezium.time.MicroTime/ NanoTime path may surface as Duration) into LocalTime via ofNanoOfDay, but only if the nanos are within 0..86400000000000 (one day). Out-of-range durations mean the source produced a time value that does not fit in a single day, so the library rejects it. Note the message text says 'milliseconds' while the check is on nanos — a known wording bug.","triggerScenarios":"Calling toLocalTime/localTime with a Duration whose toNanos() is negative or exceeds 86400000000000 (24h), e.g. a MicroTime value larger than a day, an epoch-based micros value passed without epoch adjustment, or negative durations from misparsed TIMETZ data.","commonSituations":"Debezium time.precision.mode/connect config emitting microseconds since epoch that were not converted (Debezium's MicroTimeConverter not registered); a source column storing durations or intervals rather than a time-of-day; timezone conversion shifting the value out of range.","solutions":["Register Debezium's time converters (converters=* or specific converter classes) so temporal columns arrive as correctly typed values (e.g. LocalTime via io.debezium.time.Converter)","Before calling toLocalTime, normalize epoch-micros values: LocalTime.ofNanoOfDay(micros % 86_400_000_000_000L * 1000) or use toMicroOfDay semantics","Verify the column actually stores a time-of-day; if it is an interval/duration, handle it as Duration instead of LocalTime","Clamp/validate the value at the call site and log the raw value to diagnose the producer"],"exampleFix":"// before\nLocalTime t = TemporalConversions.toLocalTime(duration); // throws if out of range\n// after\nlong nanos = duration.toNanos();\nif (nanos < 0 || nanos > 86_400_000_000_000L) {\n    nanos = ((nanos % 86_400_000_000_000L) + 86_400_000_000_000L) % 86_400_000_000_000L;\n}\nLocalTime t = LocalTime.ofNanoOfDay(nanos);","handlingStrategy":"validation","validationCode":"boolean isConvertibleDuration(Duration d) {\n    long nanos = d.toNanos();\n    return nanos >= 0 && nanos <= 86_400_000_000_000L;\n}","typeGuard":"null","tryCatchPattern":"try {\n    LocalTime t = TemporalConversions.toLocalTime(value);\n} catch (IllegalArgumentException e) {\n    LOG.warn(\"Time value out of day range: {}\", value);\n    throw new IllegalStateException(\"Invalid time-of-day in source data: \" + value, e);\n}","preventionTips":["Normalize epoch-micros/nanos with modulo one day before conversion","Configure Debezium time converters so raw micros are converted upstream","Confirm the column is a time-of-day, not an interval/duration","Log raw producer values when range errors occur to find the emitting source"],"tags":["java","cdc","time-conversion","value-out-of-range"],"backgroundTag":"value-out-of-range","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}