flowable/flowable-engine · error · FlowableIllegalArgumentException
lockDuration is null
Error message
lockDuration is null
What it means
ExternalWorkerJobAcquireBuilderImpl.topic() requires a non-null lockDuration so the engine knows how long to lock acquired jobs. A null Duration makes lock bookkeeping impossible, so Flowable throws FlowableIllegalArgumentException.
Solutions
- Pass an explicit Duration, e.g. Duration.ofMinutes(1)
- Provide a default lock duration when the configured one is null
- Validate config values at startup
Example fix
// before
builder.topic("orderTopic", parseDuration(cfg));
// after
builder.topic("orderTopic", Optional.ofNullable(parseDuration(cfg)).orElse(Duration.ofMinutes(1))); Defensive patterns
Strategy: validation
Validate before calling
if (lockDuration == null || lockDuration.isZero() || lockDuration.isNegative()) throw new IllegalArgumentException("invalid lockDuration"); Type guard
boolean validLockDuration(Duration d) { return d != null && !d.isZero() && !d.isNegative(); } Try / catch
try { builder.topic(topic, lockDuration); } catch (FlowableIllegalArgumentException e) { if (!"lockDuration is null".equals(e.getMessage())) throw e; /* fall back to default duration */ } Prevention
- Define a default lock duration constant
- Parse durations from config with explicit error handling
- Validate duration config at startup
When it happens
Trigger: Calling builder.topic("myTopic", null), e.g. when lock duration is read from config that returns null or a missing Duration parse.
Common situations: Misconfigured lock duration property; using Duration.ofMillis of an unset numeric config; refactor dropping a default duration.
Related errors
- at least one of userId or groups must be provided
- topic is null
- appsDefinitionIds is null
- Business status is null
- Candidate user is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/5736bc307847dfe1.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/ExternalWorkerJobAcquireBuilderImpl.java:56
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) {
throw new FlowableIllegalArgumentException("Cannot combine scopeType(String) with onlyBpmn() in the same query");
}
return scopeType(ScopeTypes.BPMN);
}View on GitHub (pinned to d6d39ce1c6)