flowable/flowable-engine · error · FlowableIllegalArgumentException
Can only unacquire BPMN or CMMN external job. Job with id
Error message
Can only unacquire BPMN or CMMN external job. Job with id '${jobId}' is from scope '${scopeType}' What it means
FlowableIllegalArgumentException thrown by unaquireJob when the job's scopeType is neither BPMN nor CMMN. Only external worker jobs tied to a process instance or case instance can be unacquired through this endpoint. The message includes the offending jobId and actual scope value.
Solutions
- Only unacquire jobs that were acquired through the external worker acquisition API for BPMN/CMMN scopes.
- Check the job's SCOPE_TYPE_ column in ACT_RU_EXTERNAL_JOB to see what scope it carries.
- If the job should be scoped, fix the model so the external job is created inside a process/case.
- Use the correct endpoint or engine API for standalone jobs if that is the intent.
Example fix
// before: attempting unacquire of a standalone job id DELETE-style call with jobId of a scopeless external job // after acquire and complete/unacquire only jobs returned by the external worker acquire endpoint
Defensive patterns
Strategy: validation
Validate before calling
String scope = job.getScopeType();
if (!"bpmn".equals(scope) && !"cmmn".equals(scope)) { throw new IllegalArgumentException("Unsupported scope: " + scope); } Type guard
boolean isBpmnOrCmmn(ExternalWorkerJob job) { return ScopeTypes.BPMN.equals(job.getScopeType()) || ScopeTypes.CMMN.equals(job.getScopeType()); } Try / catch
try { unaquireJob(jobId, request); } catch (FlowableIllegalArgumentException e) { if (e.getMessage().contains("Can only unacquire BPMN or CMMN")) { useCorrectEndpointForJob(); } else { throw e; } } Prevention
- Only unacquire jobs obtained via the external worker acquire API
- Check scope type before calling
- Avoid pointing clients at standalone job ids
When it happens
Trigger: POST /external-worker-job/unacquire/jobs/{jobId} where the resolved job's scopeType is null or an unsupported value (e.g. a standalone/async external job without scope, or a custom scope type).
Common situations: Jobs created outside a process/case context; upgrading Flowable versions where scope handling changed; pointing the client at a job id from a different subsystem.
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
- Variable name is required.
- worker id is required
- A group or a user is required to create an identity link.
- A request body was expected when executing the form submit.
- An assignee is required when delegating a task.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/4fcf0b61b5951665.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-external-job-rest/src/main/java/org/flowable/external/job/rest/service/api/acquire/ExternalWorkerUnacquireJobResource.java:109
managementService.unacquireExternalWorkerJob(jobId, workerId);
} else {
throw new FlowableException("Cannot unacquire BPMN job. There is no BPMN engine available");
}
} else if (ScopeTypes.CMMN.equals(job.getScopeType())) {
if (cmmnManagementService != null) {
if (restApiInterceptor != null) {
restApiInterceptor.unacquireExternalWorkerJob(job, request);
}
cmmnManagementService.unacquireExternalWorkerJob(jobId, workerId);
} else {
throw new FlowableException("Cannot unacquire CMMN job. There is no CMMN engine available");
}
} else {
throw new FlowableIllegalArgumentException(
"Can only unacquire BPMN or CMMN external job. Job with id '" + jobId + "' is from scope '" + job.getScopeType() + "'");
}
return ResponseEntity.noContent().build();
}
protected void unaquireExternalWorkerJobs(String workerId, String tenantId) {
if (managementService != null) {
if (StringUtils.isNotEmpty(tenantId)) {
managementService.unacquireAllExternalWorkerJobsForWorker(workerId, tenantId);
} else {
managementService.unacquireAllExternalWorkerJobsForWorker(workerId);
}
} else if (cmmnManagementService != null) {
if (StringUtils.isNotEmpty(tenantId)) {
cmmnManagementService.unacquireAllExternalWorkerJobsForWorker(workerId, tenantId);
} else {View on GitHub (pinned to d6d39ce1c6)