{"record":{"id":"8a34b5aa1f6554ad","repo":"flowable/flowable-engine","slug":"expression-did-not-resolve-to-a-string-or-collecti","errorCode":null,"errorMessage":"Expression did not resolve to a string or collection of strings","messagePattern":"Expression did not resolve to a string or collection of strings","errorType":"validation","errorClass":"ActivitiIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java","lineNumber":269,"sourceCode":"        if (ownerExpression != null) {\n            Object ownerExpressionValue = ownerExpression.getValue(execution);\n            String ownerValue = null;\n            if (ownerExpressionValue != null) {\n                ownerValue = ownerExpressionValue.toString();\n            }\n            task.setOwner(ownerValue);\n        }\n\n        if (candidateGroupExpressions != null && !candidateGroupExpressions.isEmpty()) {\n            for (Expression groupIdExpr : candidateGroupExpressions) {\n                Object value = groupIdExpr.getValue(execution);\n                if (value instanceof String) {\n                    List<String> candidates = extractCandidates((String) value);\n                    task.addCandidateGroups(candidates);\n                } else if (value instanceof Collection) {\n                    task.addCandidateGroups((Collection) value);\n                } else {\n                    throw new ActivitiIllegalArgumentException(\"Expression did not resolve to a string or collection of strings\");\n                }\n            }\n        }\n\n        if (candidateUserExpressions != null && !candidateUserExpressions.isEmpty()) {\n            for (Expression userIdExpr : candidateUserExpressions) {\n                Object value = userIdExpr.getValue(execution);\n                if (value instanceof String) {\n                    List<String> candiates = extractCandidates((String) value);\n                    task.addCandidateUsers(candiates);\n                } else if (value instanceof Collection) {\n                    task.addCandidateUsers((Collection) value);\n                } else {\n                    throw new ActivitiException(\"Expression did not resolve to a string or collection of strings\");\n                }\n            }\n        }\n","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java#L251-L287","documentation":"Thrown in handleAssignments when a candidateGroups (activiti:candidateGroups) expression resolves to a non-null value that is neither a String nor a Collection. The engine accepts a delimited string of group names or a Collection of them and rejects any other type as ActivitiIllegalArgumentException.","triggerScenarios":"Executing a user task whose candidateGroups expression (e.g. ${groupNames}) evaluates to an Integer, Boolean, Map, or other non-String/non-Collection object.","commonSituations":"Referencing a numeric variable in candidateGroups; a bean method returning Set wrapped differently or an array (arrays are not Collections); wrong variable assigned in a previous service task.","solutions":["Ensure the expression resolves to a String of group names (comma/semicolon separated) e.g. ${groupsString}","Ensure the expression resolves to a java.util.Collection of Strings; convert arrays with Arrays.asList(...) in the bean","Fix the variable type set upstream so it matches String or Collection<String>","Add a conversion in the referenced bean getter to return List<String>"],"exampleFix":"// before (bean returns String[])\npublic String[] getCandidateGroups() { ... }\n// after\npublic List<String> getCandidateGroups() { return Arrays.asList(...); }","handlingStrategy":"validation","validationCode":"Object v = execution.getVariable(\"groupNames\");\nif (v != null && !(v instanceof String) && !(v instanceof Collection)) {\n    throw new IllegalArgumentException(\"groupNames must be String or Collection<String>\");\n}","typeGuard":"boolean ok(Object v) { return v == null || v instanceof String || v instanceof Collection; }","tryCatchPattern":"try {\n    taskService.complete(taskId);\n} catch (ActivitiIllegalArgumentException e) {\n    if (e.getMessage().contains(\"did not resolve to a string or collection\")) { /* fix variable type */ }\n    throw e;\n}","preventionTips":["Use List<String> for candidate group variables, never arrays or Maps","Delimit multiple groups in a single String with commas if not using a Collection","Test assignment expressions during process model validation"],"tags":["expression","candidate-groups","assignment","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-18T11:17:12.947Z"}