flowable/flowable-engine · error · FlowableException

RuntimeService cannot be null, Obtain your builder instance

Error message

RuntimeService cannot be null, Obtain your builder instance from the RuntimeService to access this feature

What it means

ChangeActivityStateBuilderImpl.changeState delegates to RuntimeService.changeActivityState. The builder can be constructed without a RuntimeService (e.g. via its no-arg constructor), and in that case moving activity state is impossible, so a FlowableException is thrown telling you to obtain the builder from RuntimeService.createChangeActivityStateBuilder().

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/runtime/ChangeActivityStateBuilderImpl.java:234

        return this;
    }

    @Override
    public ChangeActivityStateBuilder localVariables(String startActivityId, Map<String, Object> localVariables) {
        if (this.localVariables == null) {
            this.localVariables = new HashMap<>();
        }

        this.localVariables.put(startActivityId, localVariables);

        return this;
    }

    @Override
    public void changeState() {
        if (runtimeService == null) {
            throw new FlowableException("RuntimeService cannot be null, Obtain your builder instance from the RuntimeService to access this feature");
        }
        runtimeService.changeActivityState(this);
    }

    public String getProcessInstanceId() {
        return processInstanceId;
    }

    public List<MoveExecutionIdContainer> getMoveExecutionIdList() {
        return moveExecutionIdList;
    }

    public List<MoveActivityIdContainer> getMoveActivityIdList() {
        return moveActivityIdList;
    }

    public List<EnableActivityIdContainer> getEnableActivityIdList() {
        return enableActivityIdList;

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Create the builder through the API: runtimeService.createChangeActivityStateBuilder()...changeState().
  2. Ensure the RuntimeService reference is injected/non-null wherever the builder is created.
  3. If writing engine-internal code, use the manager/command-context path instead of the standalone builder.
  4. Do not construct impl classes from *Impl packages in application code.

Example fix

// before
new ChangeActivityStateBuilderImpl()
    .processInstanceId(pid)
    .moveActivityIdTo("task1", "task2")
    .changeState(); // throws
// after
runtimeService.createChangeActivityStateBuilder()
    .processInstanceId(pid)
    .moveActivityIdTo("task1", "task2")
    .changeState();
Defensive patterns

Strategy: validation

Validate before calling

if (runtimeService == null) throw new IllegalStateException("Obtain ChangeActivityStateBuilder from runtimeService.createChangeActivityStateBuilder()");

Try / catch

try {
    runtimeService.createChangeActivityStateBuilder()...changeState();
} catch (FlowableException e) {
    log.error("changeActivityState failed: {}", e.getMessage());
    throw e;
}

Prevention

When it happens

Trigger: Instantiating new ChangeActivityStateBuilderImpl() directly (or via a builder obtained from a service that did not wire runtimeService) and calling changeState; frameworks deserializing/migrating builders where runtimeService was not injected.

Common situations: Custom migration tooling constructing the impl class directly; tests instantiating the builder manually; code copied from internal engine usage where CommandContext-based construction is valid but standalone callers lack the service.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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