{"record":{"id":"4828d573033c77f9","repo":"flowable/flowable-engine","slug":"expected-expression-expression-to-resolve-to-ty","errorCode":null,"errorMessage":"expected expression <expression> to resolve to <type> but it did not. Resolved value is <value>","messagePattern":"expected expression <expression> to resolve to <type> but it did not\\. Resolved value is <value>","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java","lineNumber":732,"sourceCode":"        } else if (StringUtils.hasText(recordKey.getDelegateExpression())) {\n            return resolveExpression(recordKey.getDelegateExpression(), KafkaMessageKeyProvider.class);\n        } else if (recordKey.getFixedValue() != null) {\n            String fixedValue = org.apache.commons.lang3.StringUtils.defaultIfBlank(recordKey.getFixedValue(), null);\n            return ignore -> fixedValue;\n        } else {\n            throw new FlowableException(\n                    \"The kafka recordKey value was not found for the channel model with key \" + channelModel.getKey()\n                            + \". One of fixedValue, delegateExpression or eventField should be set.\");\n        }\n    }\n\n    protected <T> T resolveExpression(String expression, Class<T> type) {\n        Object value = this.resolver.evaluate(expression, this.expressionContext);\n        if (type.isInstance(value)) {\n            return type.cast(value);\n        }\n\n        throw new FlowableException(\"expected expression \" + expression + \" to resolve to \" + type + \" but it did not. Resolved value is \" + value);\n\n    }\n\n    protected Object resolveExpression(String value) {\n        String resolvedValue = resolve(value);\n\n        return this.resolver.evaluate(resolvedValue, this.expressionContext);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    protected GenericMessageListener<ConsumerRecord<Object, Object>> createMessageListener(EventRegistry eventRegistry, InboundChannelModel inboundChannelModel) {\n        @SuppressWarnings(\"rawtypes\")\n        GenericMessageListener kafkaChannelMessageListenerAdapter = new KafkaChannelMessageListenerAdapter(eventRegistry, inboundChannelModel);\n        return kafkaChannelMessageListenerAdapter;\n    }\n\n    @Override\n    public void unregisterChannelModel(ChannelModel channelModel, String tenantId, EventRepositoryService eventRepositoryService) {","sourceCodeStart":714,"sourceCodeEnd":750,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java#L714-L750","documentation":"resolveExpression evaluates a Spring EL expression against the expression context and casts the result to the expected type. If the value is not an instance of the requested type (e.g. expected KafkaPartitionProvider but got a String), this FlowableException is thrown. It is a type mismatch between what the expression returns and what the channel processing expects.","triggerScenarios":"A delegateExpression attribute (e.g. for KafkaPartitionProvider, KafkaMessageKeyProvider, KafkaTopicProvider) resolves to a bean/value of a different type than required.","commonSituations":"Pointing delegateExpression at a plain String bean or a wrong provider class; typo'd bean name resolving to another bean of a different type; refactor renamed a provider class.","solutions":["Make the expression return the exact type expected, e.g. a bean implementing KafkaPartitionProvider.","Check the resolved bean's type with a debugger/log or by inspecting the Spring context.","Change the attribute: use eventField/fixedValue for plain values instead of delegateExpression.","Note the message prints the resolved value and the expected type name — match them."],"exampleFix":"// before\n@Bean public String partitionProvider() { return \"0\"; }\n// after\n@Bean public KafkaPartitionProvider partitionProvider() { return ignore -> 0; }","handlingStrategy":"validation","validationCode":"Object bean = applicationContext.getBean(beanName);\nif (!(bean instanceof KafkaPartitionProvider) && !(bean instanceof KafkaMessageKeyProvider)) {\n    throw new IllegalStateException(beanName + \" does not implement the required Kafka provider interface\");\n}","typeGuard":"boolean isExpectedProvider(Object v, Class<T> type) { return type.isInstance(v); }","tryCatchPattern":"try {\n    deployChannel(channelModel);\n} catch (FlowableException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"expected expression\")) {\n        log.error(\"Expression resolved to wrong type: \" + e.getMessage(), e);\n    } else { throw e; }\n}","preventionTips":["Make delegateExpression beans implement the exact provider interface Flowable expects","Keep provider bean names unambiguous and typed","Read the exception message: it names the expected type and the resolved value"],"tags":["kafka","spring-el","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"}