flowable/flowable-engine · error · FlowableException
form property '" + id + "' is required
Error message
form property '" + id + "' is required
What it means
FormPropertyHandler.submitFormProperty enforces the required flag of a BPMN form property (flowable:required="true"). If the submitted map lacks the property and no default expression is defined, FlowableException "form property '<id>' is required" is thrown. Default expressions satisfy the requirement without an explicit value.
Solutions
- Include a value for the required property in the submitted map.
- Add flowable:default="${...}" to the form property in the BPMN if a sensible default exists.
- Set flowable:required="false" if the field is genuinely optional.
- Validate the required set client-side: compare submitted keys with form properties where isRequired() before submission.
Example fix
// before
formService.submitTaskFormData(taskId, Map.of("comment", "ok")); // 'approval' is required
// after
Map<String,String> props = new HashMap<>(Map.of("comment", "ok"));
props.put("approval", "approved");
formService.submitTaskFormData(taskId, props); Defensive patterns
Strategy: validation
Validate before calling
List<String> missing = formService.getTaskFormData(taskId).getFormProperties().stream()
.filter(FormProperty::isRequired)
.map(FormProperty::getId)
.filter(id -> !properties.containsKey(id))
.collect(Collectors.toList());
if (!missing.isEmpty()) throw new IllegalArgumentException("Missing required form properties: " + missing); Try / catch
try {
formService.submitTaskFormData(taskId, properties);
} catch (FlowableException e) {
if (e.getMessage().endsWith("is required")) {
String missingId = extractPropertyId(e.getMessage());
properties.put(missingId, resolveDefaultValue(missingId));
formService.submitTaskFormData(taskId, properties);
} else { throw e; }
} Prevention
- Check FormProperty.isRequired() when building submission forms and mark fields mandatory in the UI.
- Set flowable:default expressions for required fields with predictable defaults.
- Re-validate submissions after BPMN form changes add new required fields.
- Include required-field checks in form/UI contract tests.
When it happens
Trigger: FormService.submitTaskFormData / startProcessInstanceByForm where the properties map omits a form property declared required="true" and whose flowable:default expression is absent.
Common situations: UIs with optional-but-required fields, clients submitting partial maps, BPMN updated to require a new field while existing callers don't send it, conditional fields made required incorrectly.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- form property '" + id + "' is not writable
- invalid date value " + propertyValue
- Invalid value for enum form property: + value
- A channel key detection value is required for the channel…
- A group or a user is required to create an identity link.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/dcd45933c5094b00.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/form/FormPropertyHandler.java:84
if (modelValue instanceof String) {
formProperty.setValue((String) modelValue);
} else if (type != null) {
String formValue = type.convertModelValueToFormValue(modelValue);
formProperty.setValue(formValue);
} else if (modelValue != null) {
formProperty.setValue(modelValue.toString());
}
return formProperty;
}
public void submitFormProperty(ExecutionEntity execution, Map<String, String> properties) {
if (!isWritable && properties.containsKey(id)) {
throw new FlowableException("form property '" + id + "' is not writable");
}
if (isRequired && !properties.containsKey(id) && defaultExpression == null) {
throw new FlowableException("form property '" + id + "' is required");
}
boolean propertyExists = false;
Object modelValue = null;
if (properties.containsKey(id)) {
propertyExists = true;
final String propertyValue = properties.remove(id);
if (type != null) {
modelValue = type.convertFormValueToModelValue(propertyValue);
} else {
modelValue = propertyValue;
}
} else if (defaultExpression != null) {
final Object expressionValue = defaultExpression.getValue(execution);
if (type != null && expressionValue != null) {
modelValue = type.convertFormValueToModelValue(expressionValue.toString());
} else if (expressionValue != null) {
modelValue = expressionValue.toString();
} else if (isRequired) {View on GitHub (pinned to d6d39ce1c6)