flowable/flowable-engine · error · ActivitiIllegalArgumentException

Candidate user is null

Error message

Candidate user is null

What it means

taskCandidateUser(String candidateUser) throws ActivitiIllegalArgumentException("Candidate user is null") when the candidate user id is null. The candidate-user filter drives the identity-link based candidate resolution, which requires an actual user id. Call it with a valid non-null user id or omit the filter.

Solutions

  1. Resolve the current user before building the query and skip the candidate filter if absent
  2. Return an empty result deliberately for unauthenticated contexts instead of building a query
  3. Fix the identity/lookup service so it never yields null for expected users

Example fix

// before
query.taskCandidateUser(SecurityUtils.getCurrentUserId()); // null in background job
// after
String userId = SecurityUtils.getCurrentUserId();
if (userId != null) { query.taskCandidateUser(userId); }
Defensive patterns

Strategy: validation

Validate before calling

if (candidateUser == null) {
    return Collections.emptyList(); // or skip the filter
}
query.taskCandidateUser(candidateUser);

Type guard

boolean isAuthenticatedUser(String userId) { return userId != null && !userId.trim().isEmpty(); }

Try / catch

try {
    query.taskCandidateUser(userId);
} catch (ActivitiIllegalArgumentException e) {
    log.warn("No candidate user resolved: {}", e.getMessage());
    return Collections.emptyList();
}

Prevention

When it happens

Trigger: Calling taskQuery.taskCandidateUser(null), typically when the current user was not resolvable (e.g. no authenticated principal, or a lookup returned null).

Common situations: Security context empty in a background job; userId extracted from a token/variable that was absent; task lists rendered for anonymous users without special handling.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/TaskQueryImpl.java:486

            if (delegationState == null) {
                currentOrQueryObject.noDelegationState = true;
            } else {
                currentOrQueryObject.delegationState = delegationState;
            }
        } else {
            if (delegationState == null) {
                this.noDelegationState = true;
            } else {
                this.delegationState = delegationState;
            }
        }
        return this;
    }

    @Override
    public TaskQueryImpl taskCandidateUser(String candidateUser) {
        if (candidateUser == null) {
            throw new ActivitiIllegalArgumentException("Candidate user is null");
        }

        if (orActive) {
            currentOrQueryObject.candidateUser = candidateUser;
        } else {
            this.candidateUser = candidateUser;
        }

        return this;
    }

    @Override
    public TaskQueryImpl taskInvolvedUser(String involvedUser) {
        if (involvedUser == null) {
            throw new ActivitiIllegalArgumentException("Involved user is null");
        }
        if (orActive) {
            currentOrQueryObject.involvedUser = involvedUser;

View on GitHub (pinned to d6d39ce1c6)