flowable/flowable-engine · error · FlowableIllegalArgumentException
workerId is required
Error message
workerId is required
What it means
FlowableIllegalArgumentException thrown in acquireAndLockJobs when workerId is empty or null. The engine records the workerId as the lock owner so other workers cannot complete the job; acquiring without it is rejected. Results in HTTP 400.
Source
Thrown at modules/flowable-external-job-rest/src/main/java/org/flowable/external/job/rest/service/api/acquire/ExternalWorkerAcquireJobResource.java:89
if (request.getLockDuration() != null) {
acquireBuilder.topic(request.getTopic(), request.getLockDuration());
} else {
throw new FlowableIllegalArgumentException("lockDuration is required");
}
} else {
throw new FlowableIllegalArgumentException("topic is required");
}
if (request.getScopeType() != null) {
acquireBuilder.scopeType(request.getScopeType());
}
if (StringUtils.isNotEmpty(request.getWorkerId())) {
List<AcquiredExternalWorkerJob> acquiredJobs = acquireBuilder
.acquireAndLock(request.getNumberOfTasks(), request.getWorkerId(), request.getNumberOfRetries());
return restResponseFactory.createAcquiredExternalWorkerJobResponseList(acquiredJobs);
} else {
throw new FlowableIllegalArgumentException("workerId is required");
}
}
@ApiOperation(value = "Complete an External Worker Jobs", code = 204, tags = { "Acquire and Execute" })
@ApiResponses({
@ApiResponse(code = 204, message = "Indicates the job was successfully completed."),
@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}/complete", produces = "application/json")
public ResponseEntity<?> completeJob(@PathVariable String jobId, @RequestBody ExternalWorkerJobCompleteRequest request) {
String workerId = request.getWorkerId();
if (StringUtils.isEmpty(workerId)) {
throw new FlowableIllegalArgumentException("workerId is required");
}
ExternalWorkerJob job = getExternalWorkerJobById(jobId);View on GitHub (pinned to d6d39ce1c6)
Solutions
- Set a unique workerId in the acquire request (e.g. hostname + UUID).
- Initialize the worker identity before starting the acquire loop.
- Fix JSON binding so workerId is not null.
Example fix
// before
{"topic": "invoices", "lockDuration": 60000}
// after
{"topic": "invoices", "lockDuration": 60000, "workerId": "worker-1"} Defensive patterns
Strategy: validation
Validate before calling
if (request.workerId() == null || request.workerId().isBlank()) {
throw new IllegalArgumentException("workerId is required");
} Try / catch
try {
acquire(request);
} catch (HttpClientErrorException.BadRequest e) {
log.error("Acquire rejected: {}", e.getResponseBodyAsString());
} Prevention
- Generate a stable unique workerId (hostname+UUID) at worker startup.
- Initialize worker identity before entering the acquire loop.
- Reuse the same workerId for acquire and all subsequent completions.
When it happens
Trigger: POST /external-worker/acquire/jobs with missing or empty workerId field in the request body.
Common situations: Worker instance hostname/UUID not yet initialized when the first acquire fires; config key for worker id missing; field name mismatch during JSON binding.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- lockDuration is required
- topic is required
- Can only complete BPMN or CMMN external job. Job with id '${
- Multipart request is required
- Multipart request with file content is required
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/05b347964fe68521.
Report an issue: GitHub.