flowable/flowable-engine · error · FlowableIllegalArgumentException
workerId must not be empty
Error message
workerId must not be empty
What it means
Thrown by AcquireExternalWorkerJobsCmd.execute() when workerId is null or empty. The workerId identifies the locker: it is stored as lock owner on the jobs it acquires and later checked on completion, so Flowable requires a non-empty value at acquisition time.
Solutions
- Set a non-empty workerId before starting the acquisition loop and pass it to acquireAndLock
- Validate worker configuration at startup: throw/fail deploy if workerId is blank
- Generate a stable unique id (hostname + UUID) if instances don't have a natural identity
Example fix
// before
builder.topic(topic).acquireAndLock(5, workerIdFromConfig, 60000); // empty config
// after
if (workerId == null || workerId.isEmpty()) {
throw new IllegalStateException("workerId must be configured");
}
builder.topic(topic).acquireAndLock(5, workerId, 60000); Defensive patterns
Strategy: validation
Validate before calling
if (workerId == null || workerId.isEmpty()) {
throw new IllegalArgumentException("workerId must be set before acquiring jobs");
} Type guard
boolean hasWorkerId(String id) { return id != null && !id.trim().isEmpty(); } Try / catch
try {
acquireBuilder.topic(topic).acquireAndLock(numberOfJobs, workerId, lockDuration);
} catch (FlowableIllegalArgumentException e) {
LOGGER.error("Acquire rejected: {}", e.getMessage());
} Prevention
- Initialize worker identity before starting the acquisition scheduler
- Fail deployment/startup if the workerId property is missing or blank
- Generate hostname+UUID based ids when instances lack natural identity
When it happens
Trigger: acquireAndLock(numberOfJobs, null, lockDuration); worker identity not initialized before the poll loop starts; configuration property for worker id missing so an empty string is passed.
Common situations: A worker started without its instance-name/worker-id property; race where the scheduler thread fires before configuration is bound; refactored code dropping the workerId parameter.
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
- requested number of jobs must not be smaller than 1
- topic must not be empty
- A channel key detection value is required for the channel…
- A group or a user is required to create an identity link.
- A group or a user is required to create an identity link.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/aecb12981e3a5157.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/AcquireExternalWorkerJobsCmd.java:65
this.workerId = workerId;
this.numberOfJobs = numberOfJobs;
this.builder = builder;
this.jobServiceConfiguration = jobServiceConfiguration;
}
@Override
public List<AcquiredExternalWorkerJob> execute(CommandContext commandContext) {
String topic = builder.getTopic();
if (StringUtils.isEmpty(topic)) {
throw new FlowableIllegalArgumentException("topic must not be empty");
}
if (numberOfJobs < 1) {
throw new FlowableIllegalArgumentException("requested number of jobs must not be smaller than 1");
}
if (StringUtils.isEmpty(workerId)) {
throw new FlowableIllegalArgumentException("workerId must not be empty");
}
ExternalWorkerJobEntityManager externalWorkerJobEntityManager = jobServiceConfiguration.getExternalWorkerJobEntityManager();
InternalJobManager internalJobManager = jobServiceConfiguration.getInternalJobManager();
List<ExternalWorkerJobEntity> jobs = externalWorkerJobEntityManager.findExternalJobsToExecute(builder, numberOfJobs);
int lockTimeInMillis = (int) builder.getLockDuration().abs().toMillis();
List<AcquiredExternalWorkerJob> acquiredJobs = new ArrayList<>(jobs.size());
for (ExternalWorkerJobEntity job : jobs) {
lockJob(commandContext, job, lockTimeInMillis);
Map<String, Object> variables = null;
if (internalJobManager != null) {
variables = internalJobManager.resolveVariablesForExternalWorkerJob(job);
if (job.isExclusive()) {
internalJobManager.lockJobScope(job);View on GitHub (pinned to d6d39ce1c6)