{"record":{"id":"8ba7764eec48701e","repo":"flowable/flowable-engine","slug":"timer-activityid-was-not-configured-with-a-va","errorCode":null,"errorMessage":"Timer '${activityId}' was not configured with a valid duration/time","messagePattern":"Timer '(.+?)' was not configured with a valid duration/time","errorType":"validation","errorClass":"ActivitiIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/jobexecutor/TimerDeclarationImpl.java","lineNumber":134,"sourceCode":"        // evaluating variables but other context, evaluating should happen nevertheless\n        VariableScope scopeForExpression = executionEntity;\n        if (scopeForExpression == null) {\n            scopeForExpression = NoExecutionVariableScope.getSharedInstance();\n        }\n\n        String calendarNameValue = type.calendarName;\n        if (this.calendarNameExpression != null) {\n            calendarNameValue = (String) this.calendarNameExpression.getValue(scopeForExpression);\n        }\n\n        BusinessCalendar businessCalendar = Context\n                .getProcessEngineConfiguration()\n                .getBusinessCalendarManager()\n                .getBusinessCalendar(calendarNameValue);\n\n        if (description == null) {\n            // Prevent NPE from happening in the next line\n            throw new ActivitiIllegalArgumentException(\"Timer '\" + executionEntity.getActivityId() + \"' was not configured with a valid duration/time\");\n        }\n\n        String endDateString = null;\n        String dueDateString = null;\n        Date duedate = null;\n        Date endDate = null;\n\n        if (endDateExpression != null && !(scopeForExpression instanceof NoExecutionVariableScope)) {\n            Object endDateValue = endDateExpression.getValue(scopeForExpression);\n            if (endDateValue instanceof String) {\n                endDateString = (String) endDateValue;\n            } else if (endDateValue instanceof Date) {\n                endDate = (Date) endDateValue;\n            } else if (endDateValue instanceof DateTime) {\n                // Joda DateTime support\n                duedate = ((DateTime) endDateValue).toDate();\n            } else {\n                throw new ActivitiException(\"Timer '\" + executionEntity.getActivityId() + \"' was not configured with a valid duration/time, either hand in a java.util.Date or a String in format 'yyyy-MM-dd'T'hh:mm:ss'\");","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/jobexecutor/TimerDeclarationImpl.java#L116-L152","documentation":"TimerDeclarationImpl.prepareTimerEntity resolves the timer description from a field/expression; if the resolved description is null, the business calendar would NPE later, so the engine throws ActivitiIllegalArgumentException early stating the timer activity has no valid duration/time configured. It guards the case where the timeDuration/timeDate expression evaluates to nothing.","triggerScenarios":"A timer event definition whose timeDuration/timeDate/timeCycle expression evaluates to null at runtime, e.g. ${missingVar} referencing an unset variable, and no valid ISO-8601 duration is available.","commonSituations":"Variable used in the timer expression not set before the flow reaches the timer; typo in expression variable; conditional timer definition where the field resolves to null; wrong expression returning void/null.","solutions":["Set the variable referenced by the timer expression before reaching the timer activity","Use a literal ISO-8601 duration in the BPMN (e.g. PT10M) instead of a nullable expression","Fix the expression/bean so it always returns a non-null Date or duration string","Add a default in the expression, e.g. ${dueDate != null ? dueDate : 'PT1H'}"],"exampleFix":"// before (BPMN)\n<timeDuration>${delayDuration}</timeDuration>  // variable never set\n// after\nruntimeService.setVariable(executionId, \"delayDuration\", \"PT30M\");\n// or: <timeDuration>PT30M</timeDuration>","handlingStrategy":"validation","validationCode":"Object v = runtimeService.getVariable(executionId, \"delayDuration\");\nif (v == null) throw new IllegalStateException(\"Timer duration variable must be set before reaching the timer\");","typeGuard":"boolean hasTimerValue(VariableScope scope, Expression timerExpr) {\n    return timerExpr != null && timerExpr.getValue(scope) != null;\n}","tryCatchPattern":"try {\n    processEngine.getRuntimeService().startProcessInstanceByKey(key, vars);\n} catch (ActivitiIllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"valid duration/time\")) { /* fix timer config */ }\n    else throw e;\n}","preventionTips":["Prefer literal ISO-8601 durations in BPMN over nullable expressions","Initialize all variables referenced by timer expressions at process start","Model-review timer definitions for expression nullability"],"tags":["timer","expression","bpmn"],"backgroundTag":"missing-required-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}