flowable/flowable-engine · error · ActivitiIllegalArgumentException

Category expression does not resolve to a string: %s

Error message

Category expression does not resolve to a string: %s

What it means

Thrown when a BPMN user task declares an activiti:category attribute containing an expression whose evaluation returns a non-null value that is not a String. The engine only accepts String results for the task category and refuses to silently coerce other types. The expression text is included in the message to identify the offending expression.

Source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java:194

                    } catch (NumberFormatException e) {
                        throw new ActivitiIllegalArgumentException("Priority does not resolve to a number: " + priority, e);
                    }
                } else if (priority instanceof Number) {
                    task.setPriority(((Number) priority).intValue());
                } else {
                    throw new ActivitiIllegalArgumentException("Priority expression does not resolve to a number: " +
                            activePriorityExpression.getExpressionText());
                }
            }
        }

        if (activeCategoryExpression != null) {
            final Object category = activeCategoryExpression.getValue(execution);
            if (category != null) {
                if (category instanceof String) {
                    task.setCategory((String) category);
                } else {
                    throw new ActivitiIllegalArgumentException("Category expression does not resolve to a string: " +
                            activeCategoryExpression.getExpressionText());
                }
            }
        }

        if (activeFormKeyExpression != null) {
            final Object formKey = activeFormKeyExpression.getValue(execution);
            if (formKey != null) {
                if (formKey instanceof String) {
                    task.setFormKey((String) formKey);
                } else {
                    throw new ActivitiIllegalArgumentException("FormKey expression does not resolve to a string: " +
                            activeFormKeyExpression.getExpressionText());
                }
            }
        }

        if (!skipUserTask) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Make the expression resolve to a String, e.g. use toString() in the expression: ${myObj.categoryAsString}
  2. Fix the underlying bean/variable so the referenced value is declared as a String (e.g. change the variable type set earlier in the process)
  3. If the value may be absent, wrap with a null check in the expression so it yields null (which is allowed) instead of a non-String
  4. Convert numeric/date values explicitly, e.g. ${categoryNumber.toString()} or use a formatting function

Example fix

// before (expression returns Integer)
<userTask id="task1" activiti:category="${categoryNumber}" />
// after (coerce to String)
<userTask id="task1" activiti:category="${categoryNumber.toString()}" />
Defensive patterns

Strategy: validation

Validate before calling

Object v = ((ExecutionEntity) execution).getVariable("categoryVar");
if (v != null && !(v instanceof String)) {
    throw new IllegalArgumentException("categoryVar must resolve to String, got " + v.getClass());
}

Type guard

if (category instanceof String) { task.setCategory((String) category); }

Try / catch

try {
    runtimeService.startProcessInstanceByKey(key, vars);
} catch (ActivitiIllegalArgumentException e) {
    if (e.getMessage().startsWith("Category expression")) { /* fix variable type */ }
    throw e;
}

Prevention

When it happens

Trigger: Executing a UserTask whose UserTaskActivityBehavior.execute() evaluates activeCategoryExpression (from the task definition's category expression) and Expression.getValue(execution) returns e.g. an Integer, Boolean, or POJO instead of a String.

Common situations: Setting activiti:category="${myCounter}" where myCounter is an int; pointing the category expression at a Java bean or date object; returning a non-String from a custom bean/DelegateExpression used in the category attribute.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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