flowable/flowable-engine · error · FlowableIllegalArgumentException
user id is null
Error message
user id is null
What it means
FlowableIllegalArgumentException thrown by HistoricCaseInstanceQueryImpl.startedBy(String) when the userId argument is null. The 'started by' filter is an identity restriction on the historic case instance initiator; a null identity is not a valid query criterion, so the library rejects it at build time.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricCaseInstanceQueryImpl.java:648
@Override
public HistoricCaseInstanceQueryImpl startedAfter(Date afterTime) {
if (afterTime == null) {
throw new FlowableIllegalArgumentException("after time is null");
}
if (inOrStatement) {
this.currentOrQueryObject.startedAfter = afterTime;
} else {
this.startedAfter = afterTime;
}
return this;
}
@Override
public HistoricCaseInstanceQueryImpl startedBy(String userId) {
if (userId == null) {
throw new FlowableIllegalArgumentException("user id is null");
}
if (inOrStatement) {
this.currentOrQueryObject.startedBy = userId;
} else {
this.startedBy = userId;
}
return this;
}
@Override
public HistoricCaseInstanceQueryImpl finishedBy(String userId) {
if (userId == null) {
throw new FlowableIllegalArgumentException("user id is null");
}
if (inOrStatement) {
this.currentOrQueryObject.finishedBy = userId;
} else {View on GitHub (pinned to d6d39ce1c6)
Solutions
- Pass a valid non-null userId string to startedBy().
- If the user context may be anonymous, check for null and either skip the filter or throw a domain-level 'authentication required' error.
- Validate request-supplied user identifiers before constructing the query.
Example fix
// before
query.startedBy(Authentication.getAuthenticatedUserId()); // null when not logged in
// after
String userId = Authentication.getAuthenticatedUserId();
if (userId != null) {
query.startedBy(userId);
} Defensive patterns
Strategy: validation
Validate before calling
String userId = Authentication.getAuthenticatedUserId();
if (userId != null) {
query.startedBy(userId);
} Type guard
boolean hasUserId(String userId) { return userId != null && !userId.trim().isEmpty(); } Try / catch
try {
query.startedBy(userId);
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("user id is null")) {
throw new SecurityException("Cannot filter by initiator: no authenticated user");
}
throw e;
} Prevention
- Remember Authentication.getAuthenticatedUserId() returns null for anonymous contexts — always check it.
- Validate request-supplied userId parameters (@NotBlank) before query building.
- Decide explicitly whether a missing user means 'skip filter' or 'reject request' and encode that once in a helper.
When it happens
Trigger: Calling createHistoricCaseInstanceQuery().startedBy(null); also occurs inside or() blocks since the null check precedes the inOrStatement branch.
Common situations: Passing the result of Authentication.getAuthenticatedUserId() (null for anonymous/unauthenticated contexts) into startedBy(); forwarding an optional 'userId' request parameter that was never provided.
Related errors
- after time is null
- Null planItemInstance passed
- planItemDefinitionIds is null
- involvedUser is null
- userId is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/e4798bd1eaed2d45.
Report an issue: GitHub.