flowable/flowable-engine · error · FlowableException

Unable to resolve formFieldValidationExpression without vari

Error message

Unable to resolve formFieldValidationExpression without variable container

What it means

TaskHelper throws this when a formFieldValidationExpression exists but there is no variableContainer available to evaluate it against. The engine cannot resolve a form validation expression without a variable context, so it refuses and defaults are not silently applied.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java:701

            ProcessEngineConfigurationImpl processEngineConfiguration, String formFieldValidationExpression) {

        if (StringUtils.isNotEmpty(formFieldValidationExpression)) {
            Boolean formFieldValidation = getBoolean(formFieldValidationExpression);
            if (formFieldValidation != null) {
                return formFieldValidation;
            }

            if (variableContainer != null) {
                ExpressionManager expressionManager = processEngineConfiguration.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, ProcessEngineConfigurationImpl processEngineConfiguration) {
        HistoricTaskService historicTaskService = processEngineConfiguration.getTaskServiceConfiguration().getHistoricTaskService();
        List<String> subTaskIds = historicTaskService.findHistoricTaskIdsByParentTaskIds(taskIds);
        if (subTaskIds != null && !subTaskIds.isEmpty()) {
            bulkDeleteHistoricTaskInstances(subTaskIds, processEngineConfiguration);
        }
        
        processEngineConfiguration.getCommentEntityManager().bulkDeleteCommentsForTaskIds(taskIds);
        processEngineConfiguration.getAttachmentEntityManager().bulkDeleteAttachmentsByTaskId(taskIds);
        
        processEngineConfiguration.getHistoricDetailEntityManager().bulkDeleteHistoricDetailsByTaskIds(taskIds);
        processEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableService().bulkDeleteHistoricVariableInstancesByTaskIds(taskIds);
        processEngineConfiguration.getIdentityLinkServiceConfiguration().getHistoricIdentityLinkService().bulkDeleteHistoricIdentityLinksForTaskIds(taskIds);

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Provide a variable container: evaluate within the task's execution/scope context (e.g. pass the DelegateTask or ExecutionEntity variables).
  2. Remove the formFieldValidationExpression from the task definition if validation is not context-dependent.
  3. Guard the evaluation site so the helper is only called when variableContainer != null.
  4. For out-of-context evaluation, supply a standalone VariableScope (e.g. a VariableScopeImpl populated with test variables).

Example fix

// before
taskHelper.evaluateFormFieldValidation(expression, null);
// after
if (variableContainer != null) {
    taskHelper.evaluateFormFieldValidation(expression, variableContainer);
} else {
    throw new IllegalArgumentException("formFieldValidationExpression requires a variable container");
}
Defensive patterns

Strategy: validation

Validate before calling

if (expr != null && variableContainer == null) throw new IllegalArgumentException("formFieldValidationExpression set but no variable container supplied");

Type guard

boolean canEvaluateValidation(String expr, VariableScope vc) { return expr == null || vc != null; }

Try / catch

try { /* evaluate */ } catch (FlowableException e) { if (e.getMessage().contains("without variable container")) { /* supply container or skip */ } else throw e; }

Prevention

When it happens

Trigger: Evaluating form field validation for a task definition that specifies formFieldValidationExpression, invoked through a code path where the passed variableContainer is null (e.g. no execution/scope variables available at that point).

Common situations: Calling internal APIs directly without passing the execution/variableScope; evaluating task form metadata outside a process context; unit tests that instantiate task helpers without a variable container.

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


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