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

  1. Call workerId(...) on the ExternalWorkerJobCompletionBuilder with the same id used when acquiring the job
  2. Give every worker instance a stable, non-empty workerId in configuration
  3. 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

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/a76319447919cfff. Report an issue: GitHub.