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.

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.

Appendix: 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)