{"record":{"id":"4864c34488b027d0","repo":"flowable/flowable-engine","slug":"form-property-id-is-not-writable","errorCode":null,"errorMessage":"form property '\" + id + \"' is not writable","messagePattern":"form property '\" \\+ id \\+ \"' is not writable","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/form/FormPropertyHandler.java","lineNumber":80,"sourceCode":"                modelValue = defaultExpression.getValue(NoExecutionVariableScope.getSharedInstance());\n            }\n        }\n\n        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) {","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/form/FormPropertyHandler.java#L62-L98","documentation":"FormPropertyHandler.submitFormProperty enforces the writability flag of each BPMN form property (flowable:writable=\"false\"). If a submitted property map contains a value for a read-only property, FlowableException \"form property '<id>' is not writable\" is thrown, preventing clients from injecting values into properties marked read-only.","triggerScenarios":"FormService.submitTaskFormData / startProcessInstanceByForm with a map containing a key whose FormProperty was declared writable=\"false\" in the BPMN start/task form.","commonSituations":"Generic form UIs that submit every rendered field including read-only ones, clients copying start-form values into task-form submissions, accidental reuse of a shared properties map across forms.","solutions":["Remove the read-only key from the submitted map before calling the form service.","If the field must be editable, set flowable:writable=\"true\" (or omit it) on the form property in the BPMN.","Filter submissions by querying getTaskFormData(...).getFormProperties() and only submitting writable ones.","Update the client UI to disable submission of non-writable fields."],"exampleFix":"// before\nformService.submitTaskFormData(taskId, allRenderedFields); // includes readOnly field 'status'\n// after\nMap<String,String> writable = new HashMap<>();\nfor (FormProperty p : formService.getTaskFormData(taskId).getFormProperties()) {\n    if (p.isWritable() && allRenderedFields.containsKey(p.getId())) {\n        writable.put(p.getId(), allRenderedFields.get(p.getId()));\n    }\n}\nformService.submitTaskFormData(taskId, writable);","handlingStrategy":"validation","validationCode":"Map<String,String> submit = properties.entrySet().stream()\n    .filter(e -> formProperties.stream()\n        .anyMatch(p -> p.getId().equals(e.getKey()) && p.isWritable()))\n    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));","typeGuard":null,"tryCatchPattern":"try {\n    formService.submitTaskFormData(taskId, properties);\n} catch (FlowableException e) {\n    if (e.getMessage().endsWith(\"is not writable\")) {\n        String readOnlyId = extractPropertyId(e.getMessage());\n        properties.remove(readOnlyId);\n        formService.submitTaskFormData(taskId, properties);\n    } else { throw e; }\n}","preventionTips":["Build submission maps only from FormProperty.isWritable()==true entries.","Configure UI fields with writable=false as display-only (no input binding).","Review BPMN form property attributes when forms change.","Never reuse a shared 'all fields' map across different form submissions."],"tags":["flowable","forms","read-only","validation"],"backgroundTag":"invalid-argument-value","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"}