flowable/flowable-engine · error · FlowableIllegalArgumentException
Can only complete BPMN external job with a BPMN error. Job w
Error message
Can only complete BPMN external job with a BPMN error. Job with id '${jobId}' is from scope '${scopeType}' What it means
FlowableIllegalArgumentException thrown when a BPMN error is reported for an external worker job whose scopeType is not BPMN (e.g. a CMMN case job). BPMN errors can only be applied to jobs belonging to a BPMN process instance; CMMN jobs must be terminated via the cmmnTerminate endpoint.
Source
Thrown at modules/flowable-external-job-rest/src/main/java/org/flowable/external/job/rest/service/api/acquire/ExternalWorkerAcquireJobResource.java:178
if (!workerId.equals(job.getLockOwner())) {
throw new FlowableForbiddenException(workerId + " does not hold a lock on the requested job");
}
if (job.getProcessInstanceId() != null) {
if (managementService != null) {
if (restApiInterceptor != null) {
restApiInterceptor.bpmnErrorExternalWorkerJob(job, request);
}
managementService.createExternalWorkerCompletionBuilder(job.getId(), workerId)
.variables(extractVariables(request.getVariables()))
.bpmnError(request.getErrorCode());
} else {
throw new FlowableException("Cannot complete BPMN job. There is no BPMN engine available");
}
} else {
throw new FlowableIllegalArgumentException(
"Can only complete BPMN external job with a BPMN error. Job with id '" + jobId + "' is from scope '" + job.getScopeType() + "'");
}
return ResponseEntity.noContent().build();
}
@ApiOperation(value = "Complete an External Worker Job with a cmmn terminate transition", code = 204, tags = { "Acquire and Execute" })
@ApiResponses({
@ApiResponse(code = 204, message = "Indicates the job was successfully transitioned."),
@ApiResponse(code = 400, message = "Indicates the request was invalid."),
@ApiResponse(code = 403, message = "Indicates the user does not have the rights complete the job."),
@ApiResponse(code = 404, message = "Indicates the job does not exist."),
})
@PostMapping(value = "/acquire/jobs/{jobId}/cmmnTerminate", produces = "application/json")
public ResponseEntity<?> terminateCmmnJob(@PathVariable String jobId, @RequestBody ExternalWorkerJobTerminateRequest request) {
String workerId = request.getWorkerId();
if (StringUtils.isEmpty(workerId)) {
throw new FlowableIllegalArgumentException("workerId is required");View on GitHub (pinned to d6d39ce1c6)
Solutions
- Check job.getScopeType() (available on the acquired ExternalWorkerJob) and call cmmnTerminate for CMMN jobs, bpmnError only for BPMN jobs.
- If both engines are used, restrict the acquire request or filter acquired jobs by scope type in the worker.
- Verify you are not mixing up jobIds between concurrently processed BPMN and CMMN jobs.
Example fix
// before
completionBuilder.bpmnError(errorCode);
// after
if (ScopeTypes.BPMN.equals(job.getScopeType())) {
completionBuilder.bpmnError(errorCode);
} else {
cmmnManagementService.createCmmnExternalWorkerTransitionBuilder(job.getId(), workerId).terminate();
} Defensive patterns
Strategy: validation
Validate before calling
if (job.scopeType !== 'bpmn') {
throw new Error('job ' + job.id + ' is scope ' + job.scopeType + '; use cmmnTerminate instead');
} Type guard
function isBpmnJob(job) { return job?.scopeType === 'bpmn'; } Try / catch
try {
await api.bpmnError(jobId, req);
} catch (e) {
if (e.status === 400 && /scope/.test(e.message)) {
// wrong endpoint for this job's scope; fetch job and route accordingly
return routeByScope(jobId, req);
}
throw e;
} Prevention
- Check scopeType on every acquired job before choosing bpmnError vs cmmnTerminate.
- In mixed BPMN+CMMN deployments, dispatch by scope type in one shared routing function.
- Avoid acquiring job types your worker cannot handle.
When it happens
Trigger: POST /acquire/jobs/{jobId}/bpmnError with a jobId that resolves to a job whose getScopeType() returns 'cmmn' (or any non-BPMN scope).
Common situations: Client code that acquires all external jobs indiscriminately and applies bpmnError to every failure; a mixed BPMN+CMMN deployment where the worker doesn't branch on scope type; job id mix-ups when multiple jobs are in flight.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Can only terminate CMMN external job. Job with id '${jobId}'
- Cannot query external jobs. There is no BPMN or CMMN engine
- ${externalWorkerJob} is not cmmn scoped. This command can on
- {externalWorkerJob} is not bpmn scoped. This command can onl
- Cannot complete BPMN job. There is no BPMN engine available
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/9f1899b7e0308cc6.
Report an issue: GitHub.