flowable/flowable-engine · error · FlowableIllegalArgumentException
workerId must not be empty
Error message
workerId must not be empty
What it means
Thrown by resolveJob() in AbstractExternalWorkerJobCmd when workerId is null or empty. Flowable requires the worker identity because the command later verifies that this worker actually holds the lock on the job (lock-owner check). An empty workerId means the worker did not identify itself when completing/terminating/failing a job.
Source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/AbstractExternalWorkerJobCmd.java:62
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
new UnlockExclusiveJobCmd(externalWorkerJob, jobServiceConfiguration).execute(commandContext);
}
return null;
}
protected abstract void runJobLogic(ExternalWorkerJobEntity externalWorkerJob, CommandContext commandContext);
protected ExternalWorkerJobEntity resolveJob() {
if (StringUtils.isEmpty(externalJobId)) {
throw new FlowableIllegalArgumentException("externalJobId must not be empty");
}
if (StringUtils.isEmpty(workerId)) {
throw new FlowableIllegalArgumentException("workerId must not be empty");
}
ExternalWorkerJobEntityManager externalWorkerJobEntityManager = jobServiceConfiguration.getExternalWorkerJobEntityManager();
ExternalWorkerJobEntity job = externalWorkerJobEntityManager.findById(externalJobId);
if (job == null) {
throw new FlowableObjectNotFoundException("No External Worker job found for id: " + externalJobId, ExternalWorkerJobEntity.class);
}
if (!Objects.equals(workerId, job.getLockOwner())) {
throw new FlowableIllegalArgumentException(workerId + " does not hold a lock on the requested job");
}
return job;
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Call workerId(...) on the ExternalWorkerJobCompletionBuilder with the same id used when acquiring the job
- Give every worker instance a stable, non-empty workerId in configuration
- Log the workerId at acquisition time and assert it is non-empty before executing job lifecycle commands
Example fix
// before
managementService.createExternalWorkerJobCompletionBuilder(externalJobId).complete();
// after
managementService.createExternalWorkerJobCompletionBuilder(externalJobId)
.workerId(workerId)
.complete(); Defensive patterns
Strategy: validation
Validate before calling
if (workerId == null || workerId.isEmpty()) {
throw new IllegalArgumentException("workerId must be configured before job lifecycle calls");
} Type guard
boolean hasWorkerId(String id) { return id != null && !id.trim().isEmpty(); } Try / catch
try {
completionBuilder.externalJobId(jobId).workerId(workerId).complete();
} catch (FlowableIllegalArgumentException e) {
LOGGER.error("Completion rejected: {}", e.getMessage());
} Prevention
- Configure a stable workerId per worker at startup and fail fast if blank
- Reuse the same constant/provider for workerId across acquire and completion
- Unit-test the completion path with an unset workerId to catch regressions
When it happens
Trigger: Completing, failing or terminating an external worker job without calling workerId(...) on the builder; the worker framework passing a null/empty worker identifier; constructing the command object directly with workerId unset.
Common situations: Worker instances configured without a unique workerId; refactored code where the builder field was removed; a generic job-handling wrapper that forwards only the job id.
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
- externalJobId must not be empty
- Error retrieving app engine info
- Could not find an app definition with id '<appDefinitionId>
- No action found in request body.
- No deployment id available
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/a76319447919cfff.
Report an issue: GitHub.