flowable/flowable-engine · error · FlowableIllegalArgumentException

topic is required

Error message

topic is required

What it means

FlowableIllegalArgumentException thrown in acquireAndLockJobs when the request's topic is empty or null. Acquiring external worker jobs is topic-based, so a topic must be supplied. 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:77

            @ApiResponse(code = 400, message = "Indicates the request was invalid."),
            @ApiResponse(code = 403, message = "Indicates the user does not have the rights acquire the jobs."),
    })
    @PostMapping(value = "/acquire/jobs", produces = "application/json")
    public List<AcquiredExternalWorkerJobResponse> acquireAndLockJobs(@RequestBody AcquireExternalWorkerJobRequest request) {
        ExternalWorkerJobAcquireBuilder acquireBuilder = createExternalWorkerAcquireBuilder();

        if (restApiInterceptor != null) {
            restApiInterceptor.accessAcquireExternalWorkerJobs(acquireBuilder, request);
        }

        if (StringUtils.isNotEmpty(request.getTopic())) {
            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."),

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Include a non-empty topic in the acquire request body.
  2. Ensure the configured topic name is present in the client's configuration.
  3. Validate the request client-side before sending.

Example fix

// before
{"workerId": "w1", "lockDuration": 60000}
// after
{"topic": "invoice-processing", "workerId": "w1", "lockDuration": 60000}
Defensive patterns

Strategy: validation

Validate before calling

if (request.topic() == null || request.topic().isBlank()) {
    throw new IllegalArgumentException("topic is required");
}

Try / catch

try {
    acquire(request);
} catch (HttpClientErrorException.BadRequest e) {
    log.error("Acquire rejected: {}", e.getResponseBodyAsString());
}

Prevention

When it happens

Trigger: POST /external-worker/acquire/jobs with missing topic field or topic:"" (StringUtils.isNotEmpty fails).

Common situations: Client sends an empty body or partially built request object; topic name derived from config that is unset; field naming mismatch leaving topic null after deserialization.

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/40e3469d871a6251. Report an issue: GitHub.