flowable/flowable-engine · error · FlowableException
No startFormHandler defined in process definition '
Error message
No startFormHandler defined in process definition '
What it means
After locating the process definition, GetStartFormCmd asks FormHandlerHelper.getStartFormHandler for the StartFormHandler configured in the definition's start element; when it is null the command throws FlowableException. This happens when the BPMN XML defines no start form handling (no startFormHandler/formKey configuration), so no start form data can be created.
Solutions
- Add a form definition reference to the start event: <startEvent flowable:formKey="myForm" flowable:formFieldValidation="true"/> and redeploy
- Use the form-engine API getStartFormModel/getStartFormMetadata (GetStartFormModelCmd) instead of legacy getStartFormData when forms live in the Flowable form engine
- Guard with a check for formKey via ProcessDefinitionUtil.getBpmnModel(...) start event formKey before calling
- Register a custom StartFormHandler via processEngineConfiguration.setStartFormHandlerFactory if forms are produced programmatically
Example fix
// before
StartFormData form = formService.getStartFormData(processDefinition.getId()); // NPEs/throws when no handler
// after
StartEvent start = (StartEvent) ProcessDefinitionUtil.getBpmnModel(pd.getId()).getMainProcess().getFlowElement("startEvent1");
if (start.getAttributes().containsKey("formKey")) {
StartFormData form = formService.getStartFormData(pd.getId());
} Defensive patterns
Strategy: validation
Validate before calling
StartEvent start = (StartEvent) ProcessDefinitionUtil.getBpmnModel(pdId)
.getMainProcess().getInitialFlowElement();
boolean hasForm = start.getAttributes() != null
&& start.getAttributes().containsKey("formKey"); Type guard
boolean hasStartForm(BpmnModel model) {
if (model == null || model.getMainProcess() == null) return false;
StartEvent se = (StartEvent) model.getMainProcess().getInitialFlowElement();
return se != null && se.getAttributes() != null && se.getAttributes().containsKey("formKey");
} Try / catch
try {
return formService.getStartFormData(pdId);
} catch (FlowableException e) {
if (e.getMessage() != null && e.getMessage().startsWith("No startFormHandler")) {
return null; // definition legitimately has no start form
}
throw e;
} Prevention
- Declare flowable:formKey on every start event that needs a start form and redeploy
- Keep BPMN XML under version control so formKey attributes are not dropped in manual edits
- Prefer the form-engine API (getStartFormModel) when your forms are stored in the Flowable form engine
When it happens
Trigger: getStartFormData/processDefinitionId is called for a process whose start event has no formKey/startFormHandler (typically a start event with flowable:formKey missing and no custom StartFormHandler registered).
Common situations: BPMN model with a plain start event and forms managed externally (e.g. Flowable Form engine instead of embedded form properties); XML edited manually removing the flowable:formKey attribute; older processes deployed before forms were added; confusion between legacy embedded forms and the form-engine-based APIs.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Could not find a none start event in dynamic sub process…
- No UserTask instance found for " + taskEntity
- The new process definition
- A channel key detection value is required for inbound…
- A channel key detection value is required for the channel…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/eb641c31da4a1768.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/GetStartFormCmd.java:55
public GetStartFormCmd(String processDefinitionId) {
this.processDefinitionId = processDefinitionId;
}
@Override
public StartFormData execute(CommandContext commandContext) {
ProcessDefinition processDefinition = CommandContextUtil.getProcessEngineConfiguration(commandContext).getDeploymentManager().findDeployedProcessDefinitionById(processDefinitionId);
if (processDefinition == null) {
throw new FlowableObjectNotFoundException("No process definition found for id '" + processDefinitionId + "'", ProcessDefinition.class);
}
if (Flowable5Util.isFlowable5ProcessDefinition(processDefinition, commandContext)) {
return Flowable5Util.getFlowable5CompatibilityHandler().getStartFormData(processDefinitionId);
}
FormHandlerHelper formHandlerHelper = CommandContextUtil.getProcessEngineConfiguration(commandContext).getFormHandlerHelper();
StartFormHandler startFormHandler = formHandlerHelper.getStartFormHandler(commandContext, processDefinition);
if (startFormHandler == null) {
throw new FlowableException("No startFormHandler defined in process definition '" + processDefinitionId + "'");
}
return startFormHandler.createStartFormData(processDefinition);
}
}
View on GitHub (pinned to d6d39ce1c6)