flowable/flowable-engine · error · FlowableIllegalArgumentException

Job {jobId} parent is not CMMN case

Error message

Job {jobId} parent is not CMMN case

What it means

Thrown by DefaultCmmnJobParentStateResolver.isSuspended when a job's scopeType is not 'cmmn' or its scopeId is empty, i.e. the job's parent is not a CMMN case instance. This resolver only knows how to determine suspension state via a CMMN case instance, so non-CMMN jobs are rejected with FlowableIllegalArgumentException.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/DefaultCmmnJobParentStateResolver.java:36

import org.flowable.common.engine.api.FlowableIllegalArgumentException;
import org.flowable.common.engine.api.scope.ScopeTypes;
import org.flowable.job.api.Job;
import org.flowable.job.service.InternalJobParentStateResolver;

/**
 * @author martin.grofcik
 */
public class DefaultCmmnJobParentStateResolver implements InternalJobParentStateResolver {
    private CmmnEngineConfiguration cmmnEngineConfiguration;

    public DefaultCmmnJobParentStateResolver(CmmnEngineConfiguration cmmnEngineConfiguration) {
        this.cmmnEngineConfiguration = cmmnEngineConfiguration;
    }

    @Override
    public boolean isSuspended(Job job) {
        if (!ScopeTypes.CMMN.equals(job.getScopeType()) || StringUtils.isEmpty(job.getScopeId())) {
            throw new FlowableIllegalArgumentException("Job "+ job.getId() +" parent is not CMMN case");
        }
        CaseInstance caseInstance = this.cmmnEngineConfiguration.cmmnRuntimeService.createCaseInstanceQuery().caseInstanceId(job.getScopeId()).singleResult();
        return CaseInstanceState.SUSPENDED.equals(caseInstance.getState());
    }
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Ensure only CMMN-scoped jobs are routed to this resolver (register per-scope resolvers correctly)
  2. Check the job row in the DB: ACT_RU_JOB.SCOPE_TYPE_ should be 'cmmn' and SCOPE_ID_ set to the case instance id
  3. Re-create or repair jobs missing scopeType/scopeId after migrations
  4. If the job legitimately belongs to another engine, use that engine's resolver instead

Example fix

// before
boolean suspended = defaultCmmnJobParentStateResolver.isSuspended(job); // job scopeType=bpmn
// after
if (ScopeTypes.CMMN.equals(job.getScopeType()) && job.getScopeId() != null) {
    boolean suspended = defaultCmmnJobParentStateResolver.isSuspended(job);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!"cmmn".equals(job.getScopeType()) || job.getScopeId() == null || job.getScopeId().isEmpty()) { /* route to correct resolver */ }

Type guard

boolean isCmmnJob(Job job) { return "cmmn".equals(job.getScopeType()) && job.getScopeId() != null && !job.getScopeId().isEmpty(); }

Try / catch

try { return resolver.isSuspended(job); } catch (FlowableIllegalArgumentException e) { log.warn("non-CMMN job {}: route to correct resolver", job.getId()); return false; }

Prevention

When it happens

Trigger: Job service invoking a registered suspension-state resolver for a job whose scopeType is not ScopeTypes.CMMN (e.g. a BPMN/async-executor job) or whose scopeId is null/empty.

Common situations: Deploying the CMMN engine alongside other engines and letting DefaultCmmnJobParentStateResolver handle jobs it shouldn't; jobs created without scopeType/scopeId populated (data migration or older data); misconfigured job service resolver wiring.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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