{"record":{"id":"72bbebda5014c29a","repo":"flowable/flowable-engine","slug":"hour-values-must-be-between-0-and-23","errorCode":null,"errorMessage":"Hour values must be between 0 and 23","messagePattern":"Hour values must be between 0 and 23","errorType":"validation","errorClass":"java.text.ParseException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/CronExpression.java","lineNumber":981,"sourceCode":"\n    protected int findNextWhiteSpace(int i, String s) {\n        for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\\t'); i++) {\n        }\n\n        return i;\n    }\n\n    protected void addToSet(int val, int end, int incr, int type) throws ParseException {\n\n        TreeSet<Integer> set = getSet(type);\n\n        if (type == SECOND || type == MINUTE) {\n            if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) {\n                throw new ParseException(\"Minute and Second values must be between 0 and 59\", -1);\n            }\n        } else if (type == HOUR) {\n            if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) {\n                throw new ParseException(\"Hour values must be between 0 and 23\", -1);\n            }\n        } else if (type == DAY_OF_MONTH) {\n            if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT) && (val != NO_SPEC_INT)) {\n                throw new ParseException(\"Day of month values must be between 1 and 31\", -1);\n            }\n        } else if (type == MONTH) {\n            if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) {\n                throw new ParseException(\"Month values must be between 1 and 12\", -1);\n            }\n        } else if (type == DAY_OF_WEEK) {\n            if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT) && (val != NO_SPEC_INT)) {\n                throw new ParseException(\"Day-of-Week values must be between 1 and 7\", -1);\n            }\n        }\n\n        if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) {\n            if (val != -1) {\n                set.add(val);","sourceCodeStart":963,"sourceCodeEnd":999,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/CronExpression.java#L963-L999","documentation":"CronExpression (a Quartz-derived cron parser used by Flowable's ProcessEngineConfiguration clock/timer scheduler) validates each field of the cron expression when the expression is parsed via new CronExpression(String). During storeExpressionVals/addToSet, the HOUR field value (or the end of an hour range) must be in 0-23; otherwise it throws a java.text.ParseException with this message. It is thrown at construction time, before any scheduling happens.","triggerScenarios":"Calling new CronExpression(cronString) (directly or via CronExpression.getInstance) with an hour token outside 0-23, e.g. '0 0 24 * * ?' or a range whose end exceeds 23 like '0 0 22-25 * * ?'. Only values outside the range and not the '*' ALL_SPEC sentinel trigger it.","commonSituations":"Hand-written cron strings in BPMN timer definitions or flowable.cfg job configurations; converting from formats that allow 0-24 hours; off-by-one errors like 24 for midnight instead of 0; dynamically generated ranges whose end was computed incorrectly.","solutions":["Correct the hour token in the cron string to a value in 0-23 (use 0 for midnight, not 24).","If the range end exceeds 23 (e.g. 22-25), split or clamp it: ranges that wrap midnight must be expressed as two expressions or with the '*' shorthand.","Validate the cron string before deployment with CronExpression.isValidExpression(cronString) and surface a clear config error to the user.","Wrap construction in try/catch (ParseException) at configuration-load time and fail fast with the offending expression in the log."],"exampleFix":"// before\nCronExpression expr = new CronExpression(\"0 0 24 * * ?\"); // throws\n// after\nCronExpression expr = new CronExpression(\"0 0 0 * * ?\"); // midnight = 0","handlingStrategy":"validation","validationCode":"if (!CronExpression.isValidExpression(cron)) {\n    throw new IllegalArgumentException(\"Invalid cron expression: \" + cron + \" (hours must be 0-23)\");\n}\nCronExpression expr = new CronExpression(cron);","typeGuard":null,"tryCatchPattern":"try {\n    CronExpression expr = new CronExpression(cron);\n} catch (ParseException e) {\n    throw new ConfigurationException(\"Bad hour field in cron: \" + cron, e);\n}","preventionTips":["Validate cron strings with CronExpression.isValidExpression() at config load time","Remember midnight is 0, never 24","Use hour abbreviations/ranges only within 0-23","Fail fast at startup, not at first schedule fire"],"tags":["cron","scheduling","validation","configuration"],"backgroundTag":"value-out-of-range","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}