flowable/flowable-engine · error · FlowableIllegalArgumentException

formInfo is null

Error message

formInfo is null

What it means

ProcessInstanceBuilderImpl.formVariables registers extra form-related variables for a process start. It requires a non-null FormInfo; passing null throws FlowableIllegalArgumentException because form variable resolution (fields, outcome) cannot proceed without it.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/runtime/ProcessInstanceBuilderImpl.java:240

    @Override
    public ProcessInstanceBuilder startFormVariable(String variableName, Object value) {
        if (this.startFormVariables == null) {
            this.startFormVariables = new HashMap<>();
        }
        this.startFormVariables.put(variableName, value);
        return this;
    }

    @Override
    public ProcessInstanceBuilder outcome(String outcome) {
        this.outcome = outcome;
        return this;
    }

    @Override
    public ProcessInstanceBuilder formVariables(Map<String, Object> formVariables, FormInfo formInfo, String formOutcome) {
        if (formInfo == null) {
            throw new FlowableIllegalArgumentException("formInfo is null");
        }

        if (this.extraFormVariables == null) {
            this.extraFormVariables = new HashMap<>();
        }

        if (formVariables != null) {
            this.extraFormVariables.putAll(formVariables);
        }

        this.extraFormInfo = formInfo;
        this.extraFormOutcome = formOutcome;
        return this;
    }


    @Override
    public ProcessInstanceBuilder fallbackToDefaultTenant() {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Only call formVariables when a FormInfo was actually resolved; guard with if (formInfo != null).
  2. If you have plain variables with no form, use processInstanceBuilder.variables(map) instead of formVariables.
  3. Fix the form lookup so it returns a valid FormInfo (check the form definition exists for the process).
  4. Skip form-outcome handling when there is no form.

Example fix

// before
builder.formVariables(vars, formRepositoryService.getFormInfo(...), outcome); // may pass null
// after
FormInfo formInfo = formRepositoryService.getFormInfo(...);
if (formInfo != null) {
    builder.formVariables(vars, formInfo, outcome);
} else {
    builder.variables(vars);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (formInfo == null) {
    builder.variables(vars); // plain path
} else {
    builder.formVariables(vars, formInfo, formOutcome);
}

Type guard

boolean hasForm(FormInfo fi) { return fi != null && fi.getFormKey() != null; }

Try / catch

try {
    builder.formVariables(vars, formInfo, outcome);
} catch (FlowableIllegalArgumentException e) {
    log.error("formVariables rejected: {}", e.getMessage());
    throw e;
}

Prevention

When it happens

Trigger: Calling processInstanceBuilder.formVariables(map, null, outcome); passing a FormInfo that a lookup (form repository service) returned as null because the form key/model was not found; wiring form metadata conditionally and passing null when absent.

Common situations: Start-form integration where the process has no start form defined, so the retrieved FormInfo is null; refactored code that dropped the form lookup; version changes in the form model API (task/process form handling).

Related errors


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