flowable/flowable-engine · error · FlowableIllegalArgumentException
documentation expression does not resolve to a string:
Error message
documentation expression does not resolve to a string:
What it means
The cmmn:documentation / task description attribute was written as an expression (e.g. ${...}). When Flowable evaluates it during human task creation, the result must be a String; any other type (Integer, Date, etc.) is rejected by throwing FlowableIllegalArgumentException so a wrong-typed value is not silently stored on the task.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/HumanTaskActivityBehavior.java:212
if (name instanceof String) {
taskEntity.setName((String) name);
} else {
throw new FlowableIllegalArgumentException("name expression does not resolve to a string: " + beforeContext.getName());
}
}
}
}
protected void handleTaskDescription(PlanItemInstanceEntity planItemInstanceEntity, ExpressionManager expressionManager,
TaskEntity taskEntity, CreateHumanTaskBeforeContext beforeContext) {
if (StringUtils.isNotEmpty(beforeContext.getDescription())) {
Object description = expressionManager.createExpression(beforeContext.getDescription()).getValue(planItemInstanceEntity);
if (description != null) {
if (description instanceof String) {
taskEntity.setDescription((String) description);
} else {
throw new FlowableIllegalArgumentException("documentation expression does not resolve to a string: " + beforeContext.getDescription());
}
}
}
}
protected void handleAssignee(PlanItemInstanceEntity planItemInstanceEntity, TaskService taskService,
ExpressionManager expressionManager, TaskEntity taskEntity, PlanItemInstanceEntityManager planItemInstanceEntityManager,
CreateHumanTaskBeforeContext beforeContext, MigrationContext migrationContext) {
String assigneeStringValue = null;
if (migrationContext != null && migrationContext.getAssignee() != null) {
assigneeStringValue = migrationContext.getAssignee();
} else if (StringUtils.isNotEmpty(beforeContext.getAssignee())) {
assigneeStringValue = beforeContext.getAssignee();
}
if (StringUtils.isNotEmpty(assigneeStringValue)) {View on GitHub (pinned to d6d39ce1c6)
Solutions
- Make the description expression resolve to a String, e.g. wrap it: ${toString(myVar)} or use a String variable.
- Fix the referenced variable/bean so its value is a String (or convert it at the source).
- If a static description is intended, remove the ${...} expression and write plain text in the documentation element.
- Catch FlowableIllegalArgumentException around the plan item start and log the offending expression for correction.
Example fix
// before (CMMN XML)
<cmmn:documentation>${dueDate}</cmmn:documentation>
// after
<cmmn:documentation>${dueDate.toString()}</cmmn:documentation> Defensive patterns
Strategy: type-guard
Validate before calling
Object desc = expressionManager.createExpression(descStr).getValue(scope);
if (desc != null && !(desc instanceof String)) throw new IllegalArgumentException("Description must resolve to String, got " + desc.getClass()); Type guard
boolean isValidDescription(Object v) { return v == null || v instanceof String; } Try / catch
try {
runtimeService.createPlanItemInstanceQuery()...; // start/execute plan item
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage().startsWith("documentation expression")) {
log.error("Bad description expression: {}", e.getMessage());
}
} Prevention
- Only use ${...} in documentation when the variable is guaranteed to be a String
- Convert non-String values at variable-creation time with toString()
- Unit-test CMMN models with representative expression values before deploying
When it happens
Trigger: HumanTaskActivityBehavior.execute -> handleTaskDescription, when the plan item's TaskDefinition has a non-empty description whose expression evaluates to a non-null, non-String object.
Common situations: Description expression like ${someDate} or ${count} resolving to a Date/Number; bean method returning non-String; typo pointing at the wrong variable; copy-pasting a description expression that worked for a form key into the description field.
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
- name expression does not resolve to a string:
- Priority expression does not resolve to a number:
- FormKey expression does not resolve to a string:
- Due date expression does not resolve to a Date, Instant, Loc
- Category expression does not resolve to a string:
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/f0ed9e8c49800384.
Report an issue: GitHub.