{"record":{"id":"e238e8d8ec8f22fb","repo":"flowable/flowable-engine","slug":"the-attribute-must-resolve-to-a-string-resolv-e238e8","errorCode":null,"errorMessage":"The [<attribute>] must resolve to a String. Resolved to [<class>] for [<value>]","messagePattern":"The \\[<attribute>\\] must resolve to a String\\. Resolved to \\[<class>\\] for \\[<value>\\]","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/rabbit/RabbitChannelDefinitionProcessor.java","lineNumber":167,"sourceCode":"        if (channelDefinition.getOutboundEventChannelAdapter() == null && StringUtils.hasText(routingKey)) {\n            String resolvedRoutingKey = resolve(routingKey);\n            String exchange = resolve(channelDefinition.getExchange());\n            channelDefinition\n                .setOutboundEventChannelAdapter(new RabbitOperationsOutboundEventChannelAdapter(rabbitOperations, exchange, resolvedRoutingKey));\n        }\n    }\n\n    protected String resolveExpressionAsStringOrInteger(String value, String attribute) {\n        if (!StringUtils.hasLength(value)) {\n            return null;\n        }\n        Object resolved = resolveExpression(value);\n        if (resolved instanceof String) {\n            return (String) resolved;\n        } else if (resolved instanceof Integer) {\n            return resolved.toString();\n        } else {\n            throw new IllegalStateException(\"The [\" + attribute + \"] must resolve to a String. \"\n                + \"Resolved to [\" + resolved.getClass() + \"] for [\" + value + \"]\");\n        }\n    }\n\n    protected String[] resolveQueues(RabbitInboundChannelModel channelDefinition) {\n        Collection<String> queues = channelDefinition.getQueues();\n        if (queues == null) {\n            throw new IllegalArgumentException(\"Queues in \" + channelDefinition + \" must not be null\");\n        }\n\n        List<String> resultQueues = new ArrayList<>();\n\n        for (String queue : queues) {\n            resolveQueues(resolveExpression(queue), resultQueues, channelDefinition);\n        }\n\n        return resultQueues.toArray(new String[0]);\n    }","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/rabbit/RabbitChannelDefinitionProcessor.java#L149-L185","documentation":"RabbitChannelDefinitionProcessor resolves expression/string properties of a Rabbit inbound channel definition into endpoint attributes. resolveExpressionAsStringOrInteger only accepts values that resolve to a String or Integer; anything else (e.g. Boolean, Map, bean) triggers this IllegalStateException naming the offending attribute.","triggerScenarios":"A channel definition attribute (e.g. 'concurrency', 'priority', or another string-typed property) is defined as an expression or property placeholder that resolves to a non-String/non-Integer object, such as a Boolean or a Collection bean.","commonSituations":"SpEL expression referencing the wrong bean or field type; YAML/JSON channel definition with a boolean or list where a string is expected; placeholder resolving to an unexpected type after refactoring.","solutions":["Fix the expression so it resolves to a String (or Integer, which is converted automatically)","Wrap the resolved value: use toString()-style coercion or String.valueOf in the expression","Inspect the resolved class name printed in the message to identify the wrong type","Correct the channel definition XML/JSON so the field is a string literal or resolves to one"],"exampleFix":"// before (channel definition)\n\"concurrency\": \"${kafka.listener.concurrency}\"  // resolves to Integer object bean\n// after\n\"concurrency\": \"${kafka.listener.concurrencyString}\"","handlingStrategy":"validation","validationCode":"Object resolved = resolveExpression(value);\nif (!(resolved instanceof String) && !(resolved instanceof Integer)) {\n    throw new IllegalArgumentException(\"Attribute \" + attribute + \" must resolve to String/Integer, got \" + resolved.getClass());\n}","typeGuard":"boolean isStringResolvable(Object v) {\n    return v instanceof String || v instanceof Integer;\n}","tryCatchPattern":"try {\n    String concurrency = processor.resolveExpressionAsStringOrInteger(raw, \"concurrency\");\n} catch (IllegalStateException ex) {\n    log.error(\"Channel attribute type wrong: {}\", ex.getMessage());\n}","preventionTips":["Keep string-typed channel attributes as string literals or placeholders resolving to strings","Unit-test SpEL expressions against expected result types","Avoid reusing typed beans (Boolean, Map) in string attribute positions"],"tags":["rabbitmq","spring","configuration","spel"],"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"}