flowable/flowable-engine · error · FlowableIllegalArgumentException

Child form variables can only be set when starting a plan it

Error message

Child form variables can only be set when starting a plan item instance

What it means

validateChildTaskVariablesNotSet() throws FlowableIllegalArgumentException when childTaskFormInfo (set via childTaskFormVariables) is present on a non-start transition. Child form variables, like child task variables, only apply when starting a plan item instance.

Source

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

        validateChildTaskVariablesNotSet();
        commandExecutor.execute(new CompleteStagePlanItemInstanceCmd(planItemInstanceId, variables, formVariables, formOutcome, 
                formInfo, localVariables, transientVariables, false));
    }

    @Override
    public void forceCompleteStage() {
        validateChildTaskVariablesNotSet();
        commandExecutor.execute(new CompleteStagePlanItemInstanceCmd(planItemInstanceId, variables, formVariables, formOutcome, 
                formInfo, localVariables, transientVariables, true));
    }

    protected void validateChildTaskVariablesNotSet() {
        if (childTaskVariables != null) {
            throw new FlowableIllegalArgumentException("Child task variables can only be set when starting a plan item instance");
        }

        if (childTaskFormInfo != null) {
            throw new FlowableIllegalArgumentException("Child form variables can only be set when starting a plan item instance");
        }
    }
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Complete the builder with start() when child form variables were supplied.
  2. Replace childTaskFormVariables with formVariables/variables for non-start transitions.
  3. Guard: only attach child form info when the operation is start.

Example fix

// before
builder.childTaskFormVariables(vars, formInfo, outcome).resume();
// after
builder.childTaskFormVariables(vars, formInfo, outcome).start();
Defensive patterns

Strategy: validation

Validate before calling

if (childTaskFormInfo != null && operation != Operation.START) { childTaskFormInfo = null; }

Try / catch

try { builder.resume(); } catch (FlowableIllegalArgumentException e) { throw new IllegalStateException("child form variables require start()", e); }

Prevention

When it happens

Trigger: Calling childTaskFormVariables(...) on the builder and then finishing with enable()/disable()/suspend()/resume()/terminate()/trigger() instead of start().

Common situations: Bulk transition utilities that always attach child form info; misordered refactors where the terminal operation was changed from start() to another transition.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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