{"record":{"id":"ef053c5cd4d0494f","repo":"flowable/flowable-engine","slug":"category-expression-does-not-resolve-to-a-string-ef053c","errorCode":null,"errorMessage":"Category expression does not resolve to a string: %s","messagePattern":"Category expression does not resolve to a string: (.+?)","errorType":"validation","errorClass":"ActivitiIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java","lineNumber":194,"sourceCode":"                    } catch (NumberFormatException e) {\n                        throw new ActivitiIllegalArgumentException(\"Priority does not resolve to a number: \" + priority, e);\n                    }\n                } else if (priority instanceof Number) {\n                    task.setPriority(((Number) priority).intValue());\n                } else {\n                    throw new ActivitiIllegalArgumentException(\"Priority expression does not resolve to a number: \" +\n                            activePriorityExpression.getExpressionText());\n                }\n            }\n        }\n\n        if (activeCategoryExpression != null) {\n            final Object category = activeCategoryExpression.getValue(execution);\n            if (category != null) {\n                if (category instanceof String) {\n                    task.setCategory((String) category);\n                } else {\n                    throw new ActivitiIllegalArgumentException(\"Category expression does not resolve to a string: \" +\n                            activeCategoryExpression.getExpressionText());\n                }\n            }\n        }\n\n        if (activeFormKeyExpression != null) {\n            final Object formKey = activeFormKeyExpression.getValue(execution);\n            if (formKey != null) {\n                if (formKey instanceof String) {\n                    task.setFormKey((String) formKey);\n                } else {\n                    throw new ActivitiIllegalArgumentException(\"FormKey expression does not resolve to a string: \" +\n                            activeFormKeyExpression.getExpressionText());\n                }\n            }\n        }\n\n        if (!skipUserTask) {","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java#L176-L212","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make the expression resolve to a String, e.g. use toString() in the expression: ${myObj.categoryAsString}","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)","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","Convert numeric/date values explicitly, e.g. ${categoryNumber.toString()} or use a formatting function"],"exampleFix":"// before (expression returns Integer)\n<userTask id=\"task1\" activiti:category=\"${categoryNumber}\" />\n// after (coerce to String)\n<userTask id=\"task1\" activiti:category=\"${categoryNumber.toString()}\" />","handlingStrategy":"validation","validationCode":"Object v = ((ExecutionEntity) execution).getVariable(\"categoryVar\");\nif (v != null && !(v instanceof String)) {\n    throw new IllegalArgumentException(\"categoryVar must resolve to String, got \" + v.getClass());\n}","typeGuard":"if (category instanceof String) { task.setCategory((String) category); }","tryCatchPattern":"try {\n    runtimeService.startProcessInstanceByKey(key, vars);\n} catch (ActivitiIllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Category expression\")) { /* fix variable type */ }\n    throw e;\n}","preventionTips":["Declare process variables used in string attributes as String","Use .toString() in expressions that reference non-String beans","Add a unit test asserting each category expression resolves to a String"],"tags":["expression","bpmn","user-task","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}