flowable/flowable-engine · error · FlowableIllegalArgumentException

externalJobId must not be empty

Error message

externalJobId must not be empty

What it means

resolveJob validates command inputs before touching the database. An empty/blank externalJobId makes it impossible to look up the job, so a FlowableIllegalArgumentException is thrown immediately. This is a guard against client-side mistakes when completing, failing, or unlocking an external worker job.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/AbstractExternalWorkerJobCmd.java:75

            // during the execution of the original job
            new UnlockExclusiveJobCmd(externalWorkerJob, jobServiceConfiguration).execute(commandContext);
        }
        return null;
    }

    protected abstract void runJobLogic(ExternalWorkerJobEntity externalWorkerJob, CommandContext commandContext);

    protected void moveExternalWorkerJobToExecutableJob(ExternalWorkerJobEntity externalWorkerJob, CommandContext commandContext) {
        jobServiceConfiguration.getJobManager().moveExternalWorkerJobToExecutableJob(externalWorkerJob);

        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        processEngineConfiguration.getIdentityLinkServiceConfiguration().getIdentityLinkService()
                .deleteIdentityLinksByScopeIdAndType(externalWorkerJob.getCorrelationId(), ScopeTypes.EXTERNAL_WORKER);
    }

    protected ExternalWorkerJobEntity resolveJob(CommandContext commandContext) {
        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");
        }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Pass the actual acquired job's id: new CompleteExternalWorkerJobCmd(job.getId(), workerId, variables).
  2. Validate the job id is non-empty in your worker client before building the command.
  3. Check that the acquisition result object is not null before reading its id.

Example fix

// before
new CompleteExternalWorkerJobCmd(jobId, workerId, variables); // jobId may be null
// after
Objects.requireNonNull(jobId, "externalJobId required");
if (jobId.isBlank()) throw new IllegalArgumentException("jobId required");
new CompleteExternalWorkerJobCmd(jobId, workerId, variables);
Defensive patterns

Strategy: validation

Validate before calling

if (jobId == null || jobId.isBlank()) {
    throw new IllegalArgumentException("externalJobId required");
}

Prevention

When it happens

Trigger: Invoking any external worker job command (complete/fail/release/unlock) constructed with externalJobId = null or "".

Common situations: Job id lost when mapping an acquired job DTO back into a command; variable holding the id not initialized; copying job data between systems and dropping the id field.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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