flowable/flowable-engine · error · FlowableIllegalArgumentException
Child task variables can only be set when starting a plan it
Error message
Child task variables can only be set when starting a plan item instance
What it means
PlanItemInstanceTransitionBuilderImpl.validateChildTaskVariablesNotSet() throws FlowableIllegalArgumentException when childTaskVariables were set but the transition is not a start operation. Child task variables are only meaningful when starting a plan item instance that will create a child task; any other transition (trigger, enable, disable, suspend, resume, terminate) rejects them.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceTransitionBuilderImpl.java:236
}
@Override
public void completeStage() {
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
- Use start() when child task variables are set — that is the only transition that accepts them.
- Remove the childTaskVariables(...) call for non-start transitions and pass plain variables(variables) instead.
- Branch on the intended operation before populating the builder.
Example fix
// before builder.childTaskVariables(childVars).trigger(); // invalid transition // after builder.childTaskVariables(childVars).start(); // or, for trigger: builder.variables(vars).trigger();
Defensive patterns
Strategy: validation
Validate before calling
if (childTaskVariables != null && operation != Operation.START) { childTaskVariables = null; } Try / catch
try { builder.trigger(); } catch (FlowableIllegalArgumentException e) { throw new IllegalStateException("childTaskVariables require start()", e); } Prevention
- Only set childTaskVariables on builders that will terminate with start().
- Centralize transition building so operation and child variables are validated together.
When it happens
Trigger: Calling a transition builder that did planItemInstanceBuilder.childTaskVariables(...) and then invoking trigger()/enable()/disable()/suspend()/resume()/terminate() instead of start().
Common situations: Generic transition dispatch code that sets child task variables for every operation; copying a start() example and swapping the terminal operation for trigger().
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
- Child form variables can only be set when starting a plan it
- Task ${taskId} is already deleted
- a suspended
- Setting variable is not supported for read only delegate exe
- Can only trigger a plan item that is in the ACTIVE state
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/4d8b462f1349b52c.
Report an issue: GitHub.