flowable/flowable-engine · error · FlowableIllegalArgumentException

name expression does not resolve to a string:

Error message

name expression does not resolve to a string: 

What it means

HumanTaskActivityBehavior resolves the task name from a name expression when configured. If the expression evaluates to a non-String, non-null object, the engine cannot safely assign it to the task name and throws FlowableIllegalArgumentException. Null values are tolerated (name stays unset), but wrong types are not.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/HumanTaskActivityBehavior.java:197

    protected void handleTaskName(PlanItemInstanceEntity planItemInstanceEntity, ExpressionManager expressionManager, 
                    TaskEntity taskEntity, CreateHumanTaskBeforeContext beforeContext, MigrationContext migrationContext) {
        
        String nameStringValue = null;
        if (migrationContext != null && migrationContext.getName() != null) {
            nameStringValue = migrationContext.getName();
            
        } else if (StringUtils.isNotEmpty(beforeContext.getName())) {
            nameStringValue = beforeContext.getName();
        }
        
        if (StringUtils.isNotEmpty(nameStringValue)) {
            Object name = expressionManager.createExpression(nameStringValue).getValue(planItemInstanceEntity);
            if (name != null) {
                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());
                }
            }
        }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Convert the value to a String inside the expression, e.g. ${someNumber.toString()} or ${'Task for ' + customerName}.
  2. Store a String-typed variable for the task name and reference that instead.
  3. If the value is a complex object, reference a specific string field, e.g. ${customer.name} instead of ${customer}.
  4. Update the case model/form so the variable is declared and set as a string.

Example fix

// before: numeric variable used directly -> Integer
<humanTask nameExpression="${orderNumber}"/>
// after
<humanTask nameExpression="${orderNumber.toString()}"/> // or store a String variable
Defensive patterns

Strategy: type-guard

Validate before calling

Object nameVal = caseVariables.get("taskNameVar");
if (nameVal != null && !(nameVal instanceof String)) {
    throw new IllegalArgumentException("taskNameVar must be a String, got: " + nameVal.getClass());
}

Type guard

if (nameValue instanceof String s) {
    taskEntity.setName(s); // safe assignment
}

Try / catch

try {
    caseRuntimeService.triggerPlanItemInstance(planItemId);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().startsWith("name expression does not resolve to a string")) {
        log.error("Task name expression returned non-string for case {}", caseInstanceId);
    }
    throw e;
}

Prevention

When it happens

Trigger: handleTaskName evaluates the name expression and the resulting value is neither null nor a String — e.g. an Integer, Boolean, Map, or JSON object.

Common situations: Case variable holding a number used directly as task name (e.g. ${caseCount}); data object fields returning parsed JSON objects; expressions returning collections; changes in variable type after a model update.

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/cb1722caef863516. Report an issue: GitHub.