{"record":{"id":"95a12dbba85b9a95","repo":"flowable/flowable-engine","slug":"unable-to-resolve-formfieldvalidationexpression-to-95a12d","errorCode":null,"errorMessage":"Unable to resolve formFieldValidationExpression to boolean value for ${variableContainer}","messagePattern":"Unable to resolve formFieldValidationExpression to boolean value for (.+?)","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java","lineNumber":697,"sourceCode":"        }\n    }\n\n    public static boolean isFormFieldValidationEnabled(VariableContainer variableContainer,\n            ProcessEngineConfigurationImpl processEngineConfiguration, String formFieldValidationExpression) {\n\n        if (StringUtils.isNotEmpty(formFieldValidationExpression)) {\n            Boolean formFieldValidation = getBoolean(formFieldValidationExpression);\n            if (formFieldValidation != null) {\n                return formFieldValidation;\n            }\n\n            if (variableContainer != null) {\n                ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();\n                Boolean formFieldValidationValue = getBoolean(\n                    expressionManager.createExpression(formFieldValidationExpression).getValue(variableContainer)\n                );\n                if (formFieldValidationValue == null) {\n                    throw new FlowableException(\"Unable to resolve formFieldValidationExpression to boolean value for \" + variableContainer);\n                }\n                return formFieldValidationValue;\n            }\n            throw new FlowableException(\"Unable to resolve formFieldValidationExpression without variable container\");\n        }\n        return true;\n    }\n    \n    protected static void bulkDeleteHistoricTaskInstances(Collection<String> taskIds, ProcessEngineConfigurationImpl processEngineConfiguration) {\n        HistoricTaskService historicTaskService = processEngineConfiguration.getTaskServiceConfiguration().getHistoricTaskService();\n        List<String> subTaskIds = historicTaskService.findHistoricTaskIdsByParentTaskIds(taskIds);\n        if (subTaskIds != null && !subTaskIds.isEmpty()) {\n            bulkDeleteHistoricTaskInstances(subTaskIds, processEngineConfiguration);\n        }\n        \n        processEngineConfiguration.getCommentEntityManager().bulkDeleteCommentsForTaskIds(taskIds);\n        processEngineConfiguration.getAttachmentEntityManager().bulkDeleteAttachmentsByTaskId(taskIds);\n        ","sourceCodeStart":679,"sourceCodeEnd":715,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java#L679-L715","documentation":"When evaluating a task's formFieldValidationExpression, Flowable coerces the expression result to Boolean via getBoolean. If the expression evaluates to something that is not a Boolean (so getBoolean returns null), this FlowableException is thrown because the validation flag must be a definitive boolean.","triggerScenarios":"A task/form definition carries a formFieldValidationExpression whose evaluation against the variableContainer yields a non-boolean (e.g. a String like \"yes\", a number, or null) while a variable container is present.","commonSituations":"Typo in the expression so it resolves to null; expression returning a string that is not 'true'/'false'; custom expression functions returning Object; form field configs copied from other engines with different truthiness rules.","solutions":["Fix the formFieldValidationExpression so it returns a boolean: use ${myFlag == 'true'} style comparisons instead of raw values.","Check the variable the expression reads is actually set (missing variables often evaluate to null).","Test the expression with the expression manager / in a unit test against representative variables.","If a default should apply, wrap the expression so it never resolves to a non-boolean, e.g. ${flag != null && flag == true}."],"exampleFix":"// before (bpmn xml)\n<flowable:formFieldValidationExpression>${validationLevel}</flowable:formFieldValidationExpression>\n// after\n<flowable:formFieldValidationExpression>${validationLevel == 'strict'}</flowable:formFieldValidationExpression>","handlingStrategy":"validation","validationCode":"Object v = expressionManager.createExpression(expr).getValue(variableContainer);\nif (!(v instanceof Boolean) && !(\"true\".equals(v) || \"false\".equals(v))) throw new IllegalArgumentException(\"formFieldValidationExpression must resolve to boolean\");","typeGuard":"boolean isBooleanValue(Object o) { return o instanceof Boolean || \"true\".equals(o) || \"false\".equals(o); }","tryCatchPattern":"try { /* form handling */ } catch (FlowableException e) { if (e.getMessage().contains(\"formFieldValidationExpression\")) log.error(\"Bad validation expr: {}\", e.getMessage()); else throw e; }","preventionTips":["Write validation expressions as explicit comparisons (${x == 'true'})","Unit-test form expressions with representative variable sets","Avoid raw variable values in boolean contexts"],"tags":["flowable","expression","form-validation","type-mismatch"],"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-14T11:17:12.474Z"}