{"record":{"id":"d103247fbf0e0c5f","repo":"flowable/flowable-engine","slug":"timer-needs-configuration-either-timedate-timecy","errorCode":null,"errorMessage":"Timer needs configuration (either timeDate, timeCycle or timeDuration is needed) (${id})","messagePattern":"Timer needs configuration \\(either timeDate, timeCycle or timeDuration is needed\\) \\((.+?)\\)","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TimerUtil.java","lineNumber":153,"sourceCode":"        } else if (StringUtils.isNotEmpty(timerEventDefinition.getTimeCycle())) {\n\n            businessCalendarRef = CycleBusinessCalendar.NAME;\n            expression = expressionManager.createExpression(timerEventDefinition.getTimeCycle());\n\n        } else if (StringUtils.isNotEmpty(timerEventDefinition.getTimeDuration())) {\n\n            businessCalendarRef = DurationBusinessCalendar.NAME;\n            expression = expressionManager.createExpression(timerEventDefinition.getTimeDuration());\n        }\n\n        if (StringUtils.isNotEmpty(timerEventDefinition.getCalendarName())) {\n            businessCalendarRef = timerEventDefinition.getCalendarName();\n            Expression businessCalendarExpression = expressionManager.createExpression(businessCalendarRef);\n            businessCalendarRef = businessCalendarExpression.getValue(variableContainer).toString();\n        }\n\n        if (expression == null) {\n            throw new FlowableException(\n                    \"Timer needs configuration (either timeDate, timeCycle or timeDuration is needed) (\" + timerEventDefinition.getId() + \")\");\n        }\n\n        BusinessCalendar businessCalendar = processEngineConfiguration.getBusinessCalendarManager().getBusinessCalendar(businessCalendarRef);\n\n        String dueDateString = null;\n        Date duedate = null;\n\n        Object dueDateValue = expression.getValue(variableContainer);\n        if (dueDateValue instanceof String) {\n            dueDateString = (String) dueDateValue;\n\n        } else if (dueDateValue instanceof Date) {\n            duedate = (Date) dueDateValue;\n\n        } else if (dueDateValue instanceof DateTime) {\n            JodaDeprecationLogger.LOGGER.warn(\n                    \"Using Joda-Time DateTime has been deprecated and will be removed in a future version. Timer event listener expression {} in {} resolved to a Joda-Time DateTime. \",","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TimerUtil.java#L135-L171","documentation":"TimerUtil.createTimerEntity requires the timer event definition to define exactly one timing configuration. If, after evaluating timeDate/timeCycle/timeDuration expressions, the resulting timer expression is null, Flowable throws this FlowableException because a timer without any schedule cannot fire.","triggerScenarios":"A boundary/intermediate/start timer event whose timeDate, timeCycle and timeDuration attributes are all absent or whose expressions all evaluate to null; createTimerEntity invoked via TimerUtil.timer during execution of such an event.","commonSituations":"BPMN XML with a timerEventDefinition missing child elements; timer attributes supplied only via deployment-time substitution that silently failed; refactoring that removed the timeDuration value; dynamic model edits leaving an empty timer definition.","solutions":["Add one of <timeDate>, <timeCycle> or <timeDuration> to the timerEventDefinition in the BPMN XML.","Ensure the referenced expression variable is set so the timer expression resolves to a non-null value.","Validate the process definition at deployment time (e.g. with a validator or unit test parsing the model) to catch empty timers early.","If the timer is conditionally needed, model it as a conditional/skip-able path rather than an empty timer definition."],"exampleFix":"// before\n<intermediateCatchEvent id=\"wait\"><timerEventDefinition id=\"t1\"/></intermediateCatchEvent>\n// after\n<intermediateCatchEvent id=\"wait\">\n  <timerEventDefinition id=\"t1\">\n    <timeDuration>PT10M</timeDuration>\n  </timerEventDefinition>\n</intermediateCatchEvent>","handlingStrategy":"validation","validationCode":"boolean timerConfigured(TimerEventDefinition d) {\n  return StringUtils.isNotEmpty(d.getTimeDate()) || StringUtils.isNotEmpty(d.getTimeCycle()) || StringUtils.isNotEmpty(d.getTimeDuration());\n}","typeGuard":null,"tryCatchPattern":"try { /* deploy/execute process */ } catch (FlowableException e) { if (e.getMessage().startsWith(\"Timer needs configuration\")) log.error(\"Timer {} missing timeDate/timeCycle/timeDuration\", e.getMessage()); else throw e; }","preventionTips":["Validate BPMN models at deployment with a timer-definition validator","Keep timeDate/timeCycle/timeDuration under version control and review timer XML in PRs","Never generate timerEventDefinitions programmatically without setting one timing attribute"],"tags":["flowable","bpmn","timer","missing-config"],"backgroundTag":"missing-required-config-field","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"}