flowable/flowable-engine · error · FlowableIllegalArgumentException

topic is null

Error message

topic is null

What it means

ExternalWorkerJobAcquireBuilderImpl.topic() registers a topic with a lock duration for acquiring external worker jobs. A null topic cannot be matched against jobs, so Flowable throws FlowableIllegalArgumentException.

Solutions

  1. Ensure the topic string is a non-null, non-empty value before calling topic()
  2. Provide a default topic when configuration is missing
  3. Fail fast upstream with a clear message if the topic is absent

Example fix

// before
builder.topic(config.getTopic(), Duration.ofMinutes(1));
// after
String topic = config.getTopic();
if (topic == null) throw new IllegalStateException("topic not configured");
builder.topic(topic, Duration.ofMinutes(1));
Defensive patterns

Strategy: validation

Validate before calling

if (topic == null || topic.isEmpty()) throw new IllegalArgumentException("topic must be non-empty before acquire");

Type guard

boolean validTopic(String t) { return t != null && !t.isEmpty(); }

Try / catch

try { builder.topic(topic, lockDuration); } catch (FlowableIllegalArgumentException e) { if (!"topic is null".equals(e.getMessage())) throw e; /* handle missing topic config */ }

Prevention

When it happens

Trigger: Invoking builder.topic(null, someDuration), typically when the topic string comes from an uninitialized variable or config entry.

Common situations: Topic names loaded from missing configuration keys or empty optional lookups; refactoring that removed a default topic constant.

Related errors


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

Appendix: source

Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/ExternalWorkerJobAcquireBuilderImpl.java:52

    protected final CommandExecutor commandExecutor;
    protected final JobServiceConfiguration jobServiceConfiguration;

    protected String topic;
    protected Duration lockDuration;
    protected String scopeType;
    protected String tenantId;
    protected String authorizedUser;
    protected Collection<String> authorizedGroups;

    public ExternalWorkerJobAcquireBuilderImpl(CommandExecutor commandExecutor, JobServiceConfiguration jobServiceConfiguration) {
        this.commandExecutor = commandExecutor;
        this.jobServiceConfiguration = jobServiceConfiguration;
    }

    @Override
    public ExternalWorkerJobAcquireBuilder topic(String topic, Duration lockDuration) {
        if (topic == null) {
            throw new FlowableIllegalArgumentException("topic is null");
        }

        if (lockDuration == null) {
            throw new FlowableIllegalArgumentException("lockDuration is null");
        }

        this.topic = topic;
        this.lockDuration = lockDuration;
        return this;
    }

    @Override
    public ExternalWorkerJobAcquireBuilder onlyBpmn() {
        if (ScopeTypes.CMMN.equals(scopeType)) {
            throw new FlowableIllegalArgumentException("Cannot combine onlyCmmn() with onlyBpmn() in the same query");
        }

        if (scopeType != null) {

View on GitHub (pinned to d6d39ce1c6)