flowable/flowable-engine · error · FlowableException

Unable to resolve formFieldValidationExpression to boolean v

Error message

Unable to resolve formFieldValidationExpression to boolean value for ${variableContainer}

What it means

TaskHelper.isFormFieldValidationEnabled evaluates the formFieldValidationExpression via the expression manager and requires the result to be a boolean (per getBoolean coercion). If the expression evaluates to something that cannot be interpreted as a Boolean (getBoolean returns null, e.g. a number or arbitrary object), this FlowableException is thrown because the engine cannot decide whether form field validation is on.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/task/TaskHelper.java:271

            taskServiceConfiguration.getInternalHistoryTaskManager().recordHistoryUserTaskLog(taskLogEntryBuilder);
        }
    }

    public static boolean isFormFieldValidationEnabled(VariableContainer variableContainer,
        CmmnEngineConfiguration cmmnEngineConfiguration, String formFieldValidationExpression) {
        if (StringUtils.isNotEmpty(formFieldValidationExpression)) {
            Boolean formFieldValidation = getBoolean(formFieldValidationExpression);
            if (formFieldValidation != null) {
                return formFieldValidation;
            }

            if (variableContainer != null) {
                ExpressionManager expressionManager = cmmnEngineConfiguration.getExpressionManager();
                Boolean formFieldValidationValue = getBoolean(
                    expressionManager.createExpression(formFieldValidationExpression).getValue(variableContainer)
                );
                if (formFieldValidationValue == null) {
                    throw new FlowableException("Unable to resolve formFieldValidationExpression to boolean value for " + variableContainer);
                }
                return formFieldValidationValue;
            }
            throw new FlowableException("Unable to resolve formFieldValidationExpression without variable container");
        }
        return true;
    }
    
    protected static void bulkDeleteHistoricTaskInstances(Collection<String> taskIds, CmmnEngineConfiguration cmmnEngineConfiguration) {
        HistoricTaskService historicTaskService = cmmnEngineConfiguration.getTaskServiceConfiguration().getHistoricTaskService();
        
        List<String> subTaskIds = historicTaskService.findHistoricTaskIdsByParentTaskIds(taskIds);
        if (subTaskIds != null && !subTaskIds.isEmpty()) {
            bulkDeleteHistoricTaskInstances(subTaskIds, cmmnEngineConfiguration);
        }
        
        cmmnEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableService().bulkDeleteHistoricVariableInstancesByTaskIds(taskIds);
        cmmnEngineConfiguration.getIdentityLinkServiceConfiguration().getHistoricIdentityLinkService().bulkDeleteHistoricIdentityLinksForTaskIds(taskIds);

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Fix the expression so it evaluates to a real boolean, e.g. ${userInputRequired == true} or ${someFlag}, not ${someFlagValue} returning a String/number
  2. Ensure all variables referenced by the expression are set on the variableContainer before the task form is processed
  3. Test the expression with a known variable set (e.g. via a small unit test using FlowableExpressionTestUtil or equivalent) to confirm it yields Boolean true/false
  4. If the value can legitimately be non-boolean, sanitize it beforehand and pass a boolean variable to the expression

Example fix

// before
cmmn:formFieldValidationExpression="${validationLevel}"
// after
cmmn:formFieldValidationExpression="${validationLevel > 0}"
Defensive patterns

Strategy: validation

Validate before calling

Object v = expressionValue(formFieldValidationExpression, variableContainer);
if (!(v instanceof Boolean) && !("true".equalsIgnoreCase(String.valueOf(v)) || "false".equalsIgnoreCase(String.valueOf(v)))) {
    throw new IllegalStateException("formFieldValidationExpression must be boolean, got: " + v);
}

Type guard

boolean isBooleanLike(Object v) { return v instanceof Boolean || "true".equalsIgnoreCase(String.valueOf(v)) || "false".equalsIgnoreCase(String.valueOf(v)); }

Try / catch

try { enabled = TaskHelper.isFormFieldValidationEnabled(cfg, expr, container); } catch (FlowableException e) { if (e.getMessage().startsWith("Unable to resolve formFieldValidationExpression")) { log.error("Non-boolean validation expression: {}", expr); enabled = true; } else throw e; }

Prevention

When it happens

Trigger: A CMMN task/case definition sets cmmn:formFieldValidationExpression to an expression returning a non-boolean (e.g. a string other than 'true'/'false' handled by a stricter path, a number, or null result) while a variableContainer is present; the task then renders/validates its form.

Common situations: Typo in the expression returning e.g. 'yes'/'1' or an integer; expression referencing a missing variable yielding null; copying a validation expression pattern from a place where strings are coerced differently.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/bc2c65a00375b8cd. Report an issue: GitHub.