flowable/flowable-engine · error · FlowableIllegalArgumentException

callbackIds is null or empty

Error message

callbackIds is null or empty

What it means

Flowable throws this FlowableIllegalArgumentException from HistoricProcessInstanceQuery.processInstanceCallbackIds(Set<String>) when the callbackIds set is null or empty. Callback id filters require at least one id; the query builder validates this eagerly. The set is stored on the query (or current OR query object).

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/HistoricProcessInstanceQueryImpl.java:769

            this.nameLikeIgnoreCase = nameLikeIgnoreCase.toLowerCase();
        }
        return this;
    }
    
    @Override
    public HistoricProcessInstanceQuery processInstanceCallbackId(String callbackId) {
        if (inOrStatement) {
            currentOrQueryObject.callbackId = callbackId;
        } else {
            this.callbackId = callbackId;
        }
        return this;
    }

    @Override
    public HistoricProcessInstanceQuery processInstanceCallbackIds(Set<String> callbackIds) {
        if (callbackIds == null || callbackIds.isEmpty()) {
            throw new FlowableIllegalArgumentException("callbackIds is null or empty");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.callbackIds = callbackIds;
        } else {
            this.callbackIds = callbackIds;
        }
        return this;
    }
    
    @Override
    public HistoricProcessInstanceQuery processInstanceCallbackType(String callbackType) {
        if (inOrStatement) {
            currentOrQueryObject.callbackType = callbackType;
        } else {
            this.callbackType = callbackType;
        }
        return this;
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Ensure the Set is non-null and contains at least one callback id before calling
  2. Skip the processInstanceCallbackIds call when no callback ids exist
  3. Collect ids upstream and validate emptiness before query construction

Example fix

// before
query.processInstanceCallbackIds(callbackIds);
// after
if (callbackIds != null && !callbackIds.isEmpty()) {
    query.processInstanceCallbackIds(callbackIds);
}
Defensive patterns

Strategy: validation

Validate before calling

if (callbackIds == null || callbackIds.isEmpty()) {
    throw new IllegalArgumentException("callbackIds must contain at least one id");
}

Type guard

boolean hasCallbackIds(Set<String> ids) {
    return ids != null && !ids.isEmpty();
}

Try / catch

try {
    query.processInstanceCallbackIds(callbackIds);
} catch (FlowableIllegalArgumentException e) {
    LOG.warn("Skipping callback id filter: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling processInstanceCallbackIds(null) or processInstanceCallbackIds(new HashSet<>()) on a HistoricProcessInstanceQuery.

Common situations: Aggregating callback ids from prior job submissions where no jobs were created, yielding an empty set; passing an uninitialized Set 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/8b1fa9592f66fdd2. Report an issue: GitHub.