flowable/flowable-engine · error · FlowableIllegalArgumentException

scopeContainer cannot be null

Error message

scopeContainer cannot be null

What it means

The CmmnVariableScopeResolver constructor throws FlowableIllegalArgumentException when scopeContainer is null. The resolver evaluates expressions against a scope (plan item instance or case instance); without a scope container there is nothing to resolve variables against, so construction fails fast.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/scripting/CmmnVariableScopeResolver.java:68

            "cmmnManagementService", CmmnEngineConfiguration::getCmmnManagementService,
            "taskService", CmmnEngineConfiguration::getCmmnTaskService,
            "cmmnTaskService", CmmnEngineConfiguration::getCmmnTaskService
    );

    protected static final Set<String> KEYS = Set.of(
        CASE_INSTANCE_KEY,
        PLAN_ITEM_INSTANCE_KEY,
        TASK_KEY
    );

    protected CmmnEngineConfiguration engineConfiguration;
    protected VariableContainer scopeContainer;
    protected VariableContainer inputVariableContainer;

    public CmmnVariableScopeResolver(CmmnEngineConfiguration engineConfiguration, VariableContainer scopeContainer,
            VariableContainer inputVariableContainer) {
        if (scopeContainer == null) {
            throw new FlowableIllegalArgumentException("scopeContainer cannot be null");
        }
        this.scopeContainer = scopeContainer;
        this.inputVariableContainer = inputVariableContainer;
        this.engineConfiguration = engineConfiguration;
    }

    @Override
    public boolean containsKey(Object key) {
        return inputVariableContainer.hasVariable((String) key) || KEYS.contains(key)
                || SERVICE_RESOLVERS.containsKey(key) && engineConfiguration.isServicesEnabledInScripting();
    }

    @Override
    public Object get(Object key) {
        if (SERVICE_RESOLVERS.containsKey((String) key)) {
            if (engineConfiguration.isServicesEnabledInScripting()) {
                return SERVICE_RESOLVERS.get(key).apply(engineConfiguration);
            } else {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Ensure the scope container (plan item instance or case instance entity) is loaded before building the resolver.
  2. Pass the correct VariableContainer: use the plan item instance from the delegate context, not a null.
  3. If evaluating outside a case, use a different resolver/VariableScope rather than CmmnVariableScopeResolver with null.

Example fix

// before
new CmmnVariableScopeResolver(config, null, inputContainer);
// after
VariableContainer scope = planItemInstance != null ? planItemInstance : caseInstance;
new CmmnVariableScopeResolver(config, scope, inputContainer);
Defensive patterns

Strategy: type-guard

Validate before calling

if (scopeContainer == null) throw new IllegalStateException("Cannot resolve CMMN variables without a scope container");

Type guard

VariableContainer resolveScope(PlanItemInstance p, CaseInstance c) {
    if (p != null) return p;
    if (c != null) return c;
    throw new IllegalStateException("No VariableContainer available");
}

Try / catch

try { new CmmnVariableScopeResolver(config, scope, input); } catch (FlowableIllegalArgumentException e) { throw new IllegalStateException("scopeContainer missing for expression evaluation", e); }

Prevention

When it happens

Trigger: Constructing CmmnVariableScopeResolver(engineConfiguration, null, inputVariableContainer) — usually when the calling delegate passes a null PlanItemInstanceEntity or CaseInstanceEntity into expression/script evaluation.

Common situations: Custom delegates or listeners evaluating expressions with a manually built scope that was never resolved; standalone scripting of CMMN expressions outside a running case; NPE-fix refactors that pass null through.

Related errors


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