flowable/flowable-engine · error · FlowableException

${externalWorkerJob} is not cmmn scoped. This command can on

Error message

${externalWorkerJob} is not cmmn scoped. This command can only handle cmmn scoped external worker jobs

What it means

FlowableException thrown in AbstractExternalWorkerJobCmd.execute after resolving the job: the job's scopeType is not 'cmmn', meaning the external worker job belongs to a BPMN (process) scope while this CMMN command is used against it. The command is final and hard-fails before running job logic.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/AbstractExternalWorkerJobCmd.java:48

/**
 * @author Filip Hrisafov
 */
public abstract class AbstractExternalWorkerJobCmd implements Command<Void> {

    protected final String externalJobId;
    protected final String workerId;

    protected AbstractExternalWorkerJobCmd(String externalJobId, String workerId) {
        this.externalJobId = externalJobId;
        this.workerId = workerId;
    }

    @Override
    public final Void execute(CommandContext commandContext) {
        ExternalWorkerJobEntity externalWorkerJob = resolveJob(commandContext);

        if (!ScopeTypes.CMMN.equals(externalWorkerJob.getScopeType())) {
            throw new FlowableException(externalWorkerJob + " is not cmmn scoped. This command can only handle cmmn scoped external worker jobs");
        }

        runJobLogic(externalWorkerJob, commandContext);
        if (externalWorkerJob.isExclusive()) {
            // Part of the same transaction to avoid a race condition with the
            // potentially new jobs (wrt process instance locking) that are created
            // during the execution of the original job
            CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
            new UnlockExclusiveJobCmd(externalWorkerJob, cmmnEngineConfiguration.getJobServiceConfiguration()).execute(commandContext);
        }
        return null;
    }

    protected abstract void runJobLogic(ExternalWorkerJobEntity externalWorkerJob, CommandContext commandContext);

    protected void moveExternalWorkerJobToExecutableJob(ExternalWorkerJobEntity externalWorkerJob, CommandContext commandContext) {
        CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
        cmmnEngineConfiguration.getJobServiceConfiguration().getJobManager().moveExternalWorkerJobToExecutableJob(externalWorkerJob);

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Route the job to the correct command: use the BPMN external worker task command for process-scoped jobs.
  2. Verify the job's scopeType before dispatching (inspect the external worker job entity).
  3. Separate worker polling/registration per engine (cmmn vs process) so ids cannot be mixed.

Example fix

// before
cmmnExternalWorkerTaskComplete(externalJobId); // job is process-scoped
// after
processExternalWorkerTaskComplete(externalJobId); // use BPMN command for process-scoped jobs
Defensive patterns

Strategy: try-catch

Validate before calling

ExternalWorkerJob job = externalWorkerJobQuery jobId(id).singleResult();
if (job != null && !"cmmn".equals(job.getScopeType())) routeToProcessEngine(job);

Type guard

function isCmmnScoped(job) { return job != null && "cmmn" === job.getScopeType(); }

Try / catch

try { cmmnCommand.execute(); }
catch (FlowableException e) { if (e.getMessage().endsWith("is not cmmn scoped")) { dispatchToBpmn(jobId); } }

Prevention

When it happens

Trigger: Executing a CMMN external-worker command (complete/benefit/failure) passing an externalJobId that actually references a process-scoped external worker job created by a BPMN service task.

Common situations: Sharing worker/job id bookkeeping between BPMN and CMMN engines; copy-pasting job ids between services; workers polling a combined job queue and routing ids to the wrong engine's command API.

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


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