flowable/flowable-engine · error · ActivitiIllegalArgumentException

Provided exception message is null

Error message

Provided exception message is null

What it means

TimerJobQuery.exceptionMessage(String) throws ActivitiIllegalArgumentException when the exception message argument is null. This filter finds timer jobs that failed with a specific exception text; a null value would be an empty/meaningless filter and is rejected up front.

Source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/TimerJobQueryImpl.java:178

    @Override
    public TimerJobQuery duedateLowerThenOrEquals(Date date) {
        if (date == null) {
            throw new ActivitiIllegalArgumentException("Provided date is null");
        }
        this.duedateLowerThanOrEqual = date;
        return this;
    }

    @Override
    public TimerJobQuery withException() {
        this.withException = true;
        return this;
    }

    @Override
    public TimerJobQuery exceptionMessage(String exceptionMessage) {
        if (exceptionMessage == null) {
            throw new ActivitiIllegalArgumentException("Provided exception message is null");
        }
        this.exceptionMessage = exceptionMessage;
        return this;
    }

    @Override
    public TimerJobQuery jobTenantId(String tenantId) {
        if (tenantId == null) {
            throw new ActivitiIllegalArgumentException("Provided tentant id is null");
        }
        this.tenantId = tenantId;
        return this;
    }

    @Override
    public TimerJobQuery jobTenantIdLike(String tenantIdLike) {
        if (tenantIdLike == null) {
            throw new ActivitiIllegalArgumentException("Provided tentant id is null");

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Pass a non-null exception message string (use empty string or a wildcard if you need a broader match)
  2. Only set the filter when job.getExceptionMessage() != null
  3. Query failed jobs first (e.g. .failed()) instead of filtering by an unknown message

Example fix

// before
query.exceptionMessage(job.getExceptionMessage()); // null if job has no exception
// after
String msg = job.getExceptionMessage();
if (msg != null) {
    query.exceptionMessage(msg);
}
Defensive patterns

Strategy: validation

Validate before calling

String msg = job != null ? job.getExceptionMessage() : null;
if (msg == null) {
    throw new IllegalStateException("job has no stored exception message; filter by failed state instead");
}
query.exceptionMessage(msg);

Type guard

boolean hasExceptionMessage(Job job) { return job != null && job.getExceptionMessage() != null; }

Try / catch

try {
    query.exceptionMessage(message);
} catch (ActivitiIllegalArgumentException e) {
    log.warn("No exception message available; falling back to failed-jobs query");
    query.failed();
}

Prevention

When it happens

Trigger: Calling timerJobQuery().exceptionMessage(null) — commonly because the failure's stack trace/message was never captured into the job (job not failed yet) and the retrieved message was null, then passed into the query.

Common situations: Dead-letter dashboards where the selected job has no stored exception message; retry tooling passing job.getExceptionMessage() straight back into a query without checking for null; matching on failures that were never persisted.

Related errors


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