apache/cassandra · error · IllegalArgumentException

Hour out of bounds.

Error message

Hour out of bounds.

What it means

parseTime validated the hour component of the time string and found it outside the valid range 0-23. The CQL `time` type represents a time of day, so any hour >= 24 (or negative) is rejected with this IllegalArgumentException.

Source

Thrown at src/java/org/apache/cassandra/cql3/functions/types/ParseUtils.java:411

        long second;
        long a_nanos = 0;

        String formatError = "Timestamp format must be hh:mm:ss[.fffffffff]";
        String zeros = "000000000";

        if (str == null) throw new IllegalArgumentException(formatError);
        str = str.trim();

        // Parse the time
        int firstColon = str.indexOf(':');
        int secondColon = str.indexOf(':', firstColon + 1);

        // Convert the time; default missing nanos
        if (firstColon > 0 && secondColon > 0 && secondColon < str.length() - 1)
        {
            int period = str.indexOf('.', secondColon + 1);
            hour = Integer.parseInt(str.substring(0, firstColon));
            if (hour < 0 || hour >= 24) throw new IllegalArgumentException("Hour out of bounds.");

            minute = Integer.parseInt(str.substring(firstColon + 1, secondColon));
            if (minute < 0 || minute >= 60) throw new IllegalArgumentException("Minute out of bounds.");

            if (period > 0 && period < str.length() - 1)
            {
                second = Integer.parseInt(str.substring(secondColon + 1, period));
                if (second < 0 || second >= 60) throw new IllegalArgumentException("Second out of bounds.");

                nanos_s = str.substring(period + 1);
                if (nanos_s.length() > 9) throw new IllegalArgumentException(formatError);
                if (!Character.isDigit(nanos_s.charAt(0))) throw new IllegalArgumentException(formatError);
                nanos_s = nanos_s + zeros.substring(0, 9 - nanos_s.length());
                a_nanos = Integer.parseInt(nanos_s);
            }
            else if (period > 0) throw new ParseException(formatError, -1);
            else
            {

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Clamp or convert the hour: map 24:00:00 to 23:59:59.999999999 or wrap modulo 24 if the value represents a duration.
  2. Validate hour <= 23 before calling parseTime.
  3. If it is a duration, use the CQL `duration` type / a duration parser instead of `time`.
  4. Catch IllegalArgumentException and report which component was out of bounds.

Example fix

// before
long nanos = ParseUtils.parseTime("24:00:00"); // throws
// after
String s = "24:00:00";
if (s.startsWith("24:")) s = "23:59:59.999999999"; // end-of-day convention
long nanos = ParseUtils.parseTime(s);
Defensive patterns

Strategy: validation

Validate before calling

int hour = Integer.parseInt(s.substring(0, s.indexOf(':')));
if (hour < 0 || hour > 23) throw new IllegalArgumentException("hour must be 0-23: " + hour);

Try / catch

try { return ParseUtils.parseTime(s); }
catch (IllegalArgumentException e) { log.warn("Invalid hour in time '{}'", s); throw e; }

Prevention

When it happens

Trigger: Calling ParseUtils.parseTime("24:00:00"), "25:15:30", "99:00:00" or any negative hour such as "-1:00:00" — the hour substring before the first colon parses to an int outside [0, 23].

Common situations: Durations encoded as times ("30:00:00" meaning 30 hours), 24 as end-of-day from midnight-inclusive ranges, clock data in 1-12 or 1-24 conventions, or off-by-one generation of hour values.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/2d7f3afa222ed88e. Report an issue: GitHub.