{"record":{"id":"dbedf8666b1894e7","repo":"flowable/flowable-engine","slug":"minute-and-second-values-must-be-between-0-and-59","errorCode":null,"errorMessage":"Minute and Second values must be between 0 and 59","messagePattern":"Minute and Second values must be between 0 and 59","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":977,"sourceCode":"        }\n\n        return i;\n    }\n\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        }","sourceCodeStart":959,"sourceCodeEnd":995,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/CronExpression.java#L959-L995","documentation":"Flowable's CronExpression validates each parsed field against its legal numeric range. When a set of second or minute values is built (in addToSet, called from storeExpressionVals while parsing), any value below 0 or above 59 (including an end-of-range value > 59) is rejected — except the internal ALL_SPEC sentinel — with this ParseException. It fires at expression-parse time with position -1 because the offending field is only known as a set at that point.","triggerScenarios":"new CronExpression(expr) where the seconds or minutes field contains a number > 59 or negative — e.g. '60 * * * * ?' (60 seconds), '0 75 * * * ?' (75 minutes), or computed values produced by arithmetic in generated expressions.","commonSituations":"Confusing seconds with milliseconds in generated timers (60000 ms written into the seconds field); copying Unix cron (5 fields, minute first, some allow 60 in edge tooling) into the 6/7-field Quartz format incorrectly; building expressions programmatically with offsets that overflow the 0-59 range instead of being normalized modulo 60.","solutions":["Keep seconds and minutes in the range 0-59; normalize any computed value with Math.floorMod(value, 60) before building the expression","If the intent was an interval, use the increment form instead of an out-of-range value, e.g. '0/90' is still invalid — instead use '0 0/2 * * * ?' style fields or restructure the schedule","Convert duration-style inputs (milliseconds) to a proper schedule before rendering a cron expression; never paste a duration number into a seconds field","Pre-validate with CronExpression.isValidExpression(expr) and surface a clear message to users configuring timers"],"exampleFix":"// before\nString cron = \"0 \" + intervalSeconds + \" * * * ?\"; // intervalSeconds could be 90\n// after\nint normalized = Math.floorMod(intervalSeconds, 60);\nString cron = \"0 \" + normalized + \" * * * ?\"; // always 0-59","handlingStrategy":"validation","validationCode":"int normalize60(int v) { return Math.floorMod(v, 60); }\n// before building the expression\nif (seconds < 0 || seconds > 59 || minutes < 0 || minutes > 59) {\n    throw new IllegalArgumentException(\"Seconds/minutes must be 0-59\");\n}\nString expr = seconds + \" \" + minutes + \" \" + hours + \" * * ?\";\nif (!CronExpression.isValidExpression(expr)) {\n    throw new IllegalArgumentException(\"Invalid cron expression: \" + expr);\n}","typeGuard":"boolean isValidSecondOrMinute(int v) {\n    return v >= 0 && v <= 59;\n}","tryCatchPattern":"try {\n    CronExpression cron = new CronExpression(expr);\n} catch (ParseException e) {\n    throw new ConfigurationException(\"Cron seconds/minutes must be 0-59: \" + expr, e);\n}","preventionTips":["Normalize computed time components with Math.floorMod(v, 60) before string-building","Never place duration/millisecond values directly into seconds or minutes fields","Convert Unix 5-field crons to the 6/7-field Quartz format rather than pasting them directly","Validate user-configured expressions with isValidExpression and reject them at input time"],"tags":["cron","scheduling","validation","range-check"],"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"}