{"record":{"id":"ba9fb6200c3bdcbd","repo":"flowable/flowable-engine","slug":"failed-to-parse-scheduler-expression","errorCode":null,"errorMessage":"Failed to parse scheduler expression: ","messagePattern":"Failed to parse scheduler expression: ","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/AdvancedSchedulerResolverWithTimeZone.java","lineNumber":46,"sourceCode":"public class AdvancedSchedulerResolverWithTimeZone implements AdvancedSchedulerResolver {\n\n    @Override\n    public Date resolve(String duedateDescription, ClockReader clockReader, TimeZone timeZone) {\n        Calendar nextRun = null;\n\n        try {\n            if (duedateDescription.startsWith(\"R\")) {\n                nextRun = new DurationHelper(duedateDescription, clockReader).getCalendarAfter(clockReader.getCurrentCalendar(timeZone));\n            } else {\n                CronExpression cronExpression = new CronExpression(duedateDescription, clockReader);\n                cronExpression.setTimeZone(timeZone);\n                Date nextRunDate = cronExpression.getTimeAfter(clockReader.getCurrentCalendar(timeZone).getTime());\n                nextRun = new GregorianCalendar();\n                nextRun.setTime(nextRunDate);\n            }\n\n        } catch (Exception e) {\n            throw new FlowableException(\"Failed to parse scheduler expression: \" + duedateDescription, e);\n        }\n\n        return nextRun == null ? null : nextRun.getTime();\n    }\n\n}\n","sourceCodeStart":28,"sourceCodeEnd":53,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/AdvancedSchedulerResolverWithTimeZone.java#L28-L53","documentation":"AdvancedSchedulerResolverWithTimeZone.resolve() wraps every failure while computing the next run date of a cron expression in a FlowableException with this message. It means the timer/duedate description (cron expression plus optional timezone) could not be parsed or evaluated, and the original cause (often a ParseException from CronExpression) is chained. This is a configuration/definition problem, not a transient runtime fault.","triggerScenarios":"Calling resolve(duedateDescription, timeZone, clockReader) with a malformed cron expression string, an expression that CronExpression rejects (bad 'L'/'#' usage, too few fields, invalid month/day names), or a description that fails CronExpression construction/evaluation inside the try block.","commonSituations":"Timer event definitions in BPMN XML with hand-written cron strings; admin-entered job/timer definitions; expressions copied from Quartz v1 docs that use unsupported combinations (e.g. both day-of-month and day-of-week restricted); typos in month/day names; missing cron fields after refactoring.","solutions":["Print/inspect the chained cause (e.getCause()) to get the exact ParseException from CronExpression and fix the cron string","Validate the expression with a cron validator (or construct a CronExpression directly in a unit test) before deploying the process definition","Ensure the expression has at least 6 fields (second minute hour day-of-month month day-of-week, optional year) and leaves either day-of-month or day-of-week as '?'","If the duedate is meant to be a duration (e.g. PT10M) not a cron, do not pass it to the cron-based resolver"],"exampleFix":"// before\nString duedate = \"0 0 12 ? * MON,FRI-L\"; // invalid: L mixed with list in day-of-week\nresolver.resolve(duedate, timeZone, clockReader);\n// after\nString duedate = \"0 0 12 ? * MON,FRI\"; // valid expression\nresolver.resolve(duedate, timeZone, clockReader);","handlingStrategy":"try-catch","validationCode":"public static void validateCron(String expr) {\n    try { new CronExpression(expr, new DefaultClockReader()); }\n    catch (Exception e) { throw new IllegalArgumentException(\"Invalid cron: \" + expr, e); }\n}","typeGuard":"boolean isUsableCron(String s) { return s != null && s.trim().split(\"\\\\s+\").length >= 6; }","tryCatchPattern":"try {\n    Date next = resolver.resolve(duedate, timeZone, clockReader);\n} catch (FlowableException e) {\n    logger.error(\"Bad schedule definition '\" + duedate + \"'\", e.getCause());\n    throw new ConfigurationException(\"Fix timer definition: \" + duedate, e);\n}","preventionTips":["Validate cron expressions in a unit test at build time for every BPMN timer definition","Always log e.getCause() — the real ParseException is chained","Use 6/7-field Quartz-style cron, with '?' in one of the day fields","Keep cron strings in reviewed configuration, not string-concatenated templates"],"tags":["cron","scheduler","flowable","configuration"],"backgroundTag":"invalid-cron-expression","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"}