{"record":{"id":"f23ed018b2635dfe","repo":"flowable/flowable-engine","slug":"can-only-use-a-collection-of-string-elements-for-r-f23ed0","errorCode":null,"errorMessage":"Can only use a collection of String elements for referencing channel model key","messagePattern":"Can only use a collection of String elements for referencing channel model key","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/SendEventTaskActivityBehavior.java","lineNumber":194,"sourceCode":"        List<String> channelKeys = new ArrayList<>();\n\n        Map<String, List<ExtensionElement>> extensionElements = execution.getCurrentFlowElement().getExtensionElements();\n        if (extensionElements != null) {\n            List<ExtensionElement> channelKeyElements = extensionElements.get(\"channelKey\");\n            if (channelKeyElements != null && !channelKeyElements.isEmpty()) {\n                String channelKey = channelKeyElements.get(0).getElementText();\n                if (StringUtils.isNotEmpty(channelKey)) {\n                    ExpressionManager expressionManager = CommandContextUtil.getProcessEngineConfiguration(commandContext).getExpressionManager();\n                    Expression expression = expressionManager.createExpression(channelKey);\n                    Object resolvedChannelKey = expression.getValue(execution);\n                    if (resolvedChannelKey instanceof Collection) {\n                        for (Object next : (Collection) resolvedChannelKey) {\n                            if (next instanceof String) {\n                                String[] keys = ((String) next).split(\",\");\n                                channelKeys.addAll(Arrays.asList(keys));\n\n                            } else {\n                                throw new FlowableIllegalArgumentException(\"Can only use a collection of String elements for referencing channel model key\");\n\n                            }\n                        }\n\n                    } else if (resolvedChannelKey instanceof String) {\n                        String[] keys = ((String) resolvedChannelKey).split(\",\");\n                        channelKeys.addAll(Arrays.asList(keys));\n\n                    }\n                }\n            }\n        }\n\n        if (channelKeys.isEmpty()) {\n            if (!sendOnSystemChannel) {\n                // If the event is going to be send on the system channel then it is allowed to not define any other channels\n                throw new FlowableException(\"No channel keys configured for \" + execution);\n            } else {","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/SendEventTaskActivityBehavior.java#L176-L212","documentation":"SendEventTaskActivityBehavior.getChannelModels throws FlowableIllegalArgumentException when the resolved channel key expression yields a collection containing non-String elements. Channel keys must be Strings (optionally comma-separated lists), and any other element type makes channel resolution ambiguous.","triggerScenarios":"A send event task's channelKey expression resolves to a Collection whose elements are not Strings — e.g. a list of Integers, domain objects, or maps returned from a variable or bean expression.","commonSituations":"Passing a List<Long> of channel ids instead of String keys; a delegate/bean that builds the collection with the wrong element type; a variable set from JSON data where numbers were not converted to Strings.","solutions":["Ensure the collection variable contains only String elements before the send event task executes","Convert the collection (e.g. map each element to String) in a preceding service task or delegate","If keys come from a bean expression, fix the bean to return List<String>","Split numeric ids into their String keys when building the variable"],"exampleFix":"// before\nList<Long> channelIds = repository.findIds();\nexecution.setVariable(\"channels\", channelIds);\n// after\nList<String> channelKeys = repository.findIds().stream().map(String::valueOf).collect(Collectors.toList());\nexecution.setVariable(\"channels\", channelKeys);","handlingStrategy":"type-guard","validationCode":"// Validate channel variable before the send event task runs\nObject channels = execution.getVariable(\"channels\");\nboolean valid = channels instanceof Collection\n    && ((Collection<?>) channels).stream().allMatch(String.class::isInstance);","typeGuard":"public static boolean isStringCollection(Object o) {\n    return o instanceof Collection && ((Collection<?>) o).stream().allMatch(String.class::isInstance);\n}","tryCatchPattern":null,"preventionTips":["Type channel-key collections as List<String> at the producing side","Convert numeric ids to String keys before setting the variable","Add a pre-task validation service task for dynamic channel collections"],"tags":["type-mismatch","collection","event-registry","flowable"],"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"}