{"record":{"id":"dcd45933c5094b00","repo":"flowable/flowable-engine","slug":"form-property-id-is-required","errorCode":null,"errorMessage":"form property '\" + id + \"' is required","messagePattern":"form property '\" \\+ id \\+ \"' is required","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/form/FormPropertyHandler.java","lineNumber":84,"sourceCode":"        if (modelValue instanceof String) {\n            formProperty.setValue((String) modelValue);\n        } else if (type != null) {\n            String formValue = type.convertModelValueToFormValue(modelValue);\n            formProperty.setValue(formValue);\n        } else if (modelValue != null) {\n            formProperty.setValue(modelValue.toString());\n        }\n\n        return formProperty;\n    }\n\n    public void submitFormProperty(ExecutionEntity execution, Map<String, String> properties) {\n        if (!isWritable && properties.containsKey(id)) {\n            throw new FlowableException(\"form property '\" + id + \"' is not writable\");\n        }\n\n        if (isRequired && !properties.containsKey(id) && defaultExpression == null) {\n            throw new FlowableException(\"form property '\" + id + \"' is required\");\n        }\n        boolean propertyExists = false;\n        Object modelValue = null;\n        if (properties.containsKey(id)) {\n            propertyExists = true;\n            final String propertyValue = properties.remove(id);\n            if (type != null) {\n                modelValue = type.convertFormValueToModelValue(propertyValue);\n            } else {\n                modelValue = propertyValue;\n            }\n        } else if (defaultExpression != null) {\n            final Object expressionValue = defaultExpression.getValue(execution);\n            if (type != null && expressionValue != null) {\n                modelValue = type.convertFormValueToModelValue(expressionValue.toString());\n            } else if (expressionValue != null) {\n                modelValue = expressionValue.toString();\n            } else if (isRequired) {","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/form/FormPropertyHandler.java#L66-L102","documentation":"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.","triggerScenarios":"FormService.submitTaskFormData / startProcessInstanceByForm where the properties map omits a form property declared required=\"true\" and whose flowable:default expression is absent.","commonSituations":"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.","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."],"exampleFix":"// before\nformService.submitTaskFormData(taskId, Map.of(\"comment\", \"ok\")); // 'approval' is required\n// after\nMap<String,String> props = new HashMap<>(Map.of(\"comment\", \"ok\"));\nprops.put(\"approval\", \"approved\");\nformService.submitTaskFormData(taskId, props);","handlingStrategy":"validation","validationCode":"List<String> missing = formService.getTaskFormData(taskId).getFormProperties().stream()\n    .filter(FormProperty::isRequired)\n    .map(FormProperty::getId)\n    .filter(id -> !properties.containsKey(id))\n    .collect(Collectors.toList());\nif (!missing.isEmpty()) throw new IllegalArgumentException(\"Missing required form properties: \" + missing);","typeGuard":null,"tryCatchPattern":"try {\n    formService.submitTaskFormData(taskId, properties);\n} catch (FlowableException e) {\n    if (e.getMessage().endsWith(\"is required\")) {\n        String missingId = extractPropertyId(e.getMessage());\n        properties.put(missingId, resolveDefaultValue(missingId));\n        formService.submitTaskFormData(taskId, properties);\n    } else { throw e; }\n}","preventionTips":["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."],"tags":["flowable","forms","required-field","validation"],"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"}