{"record":{"id":"4f1d5980c9a50dc1","repo":"flowable/flowable-engine","slug":"topic-in-topic-partition-in-channel-model-chann","errorCode":null,"errorMessage":"topic in topic partition in channel model [ <channelModel.getKey()> ] must resolve to a non empty string","messagePattern":"topic in topic partition in channel model \\[ <channelModel\\.getKey\\(\\)> \\] must resolve to a non empty string","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java","lineNumber":593,"sourceCode":"                throw new IllegalStateException(\n                    \"topicPattern in channel model [ \" + channelModel + \" ] must resolve to a Pattern or String, not \" + resolved.getClass());\n            }\n        }\n\n        return pattern;\n    }\n\n    protected Collection<TopicPartitionOffset> resolveTopicPartitions(KafkaInboundChannelModel channelModel) {\n        Collection<KafkaInboundChannelModel.TopicPartition> topicPartitions = channelModel.getTopicPartitions();\n        if (topicPartitions == null || topicPartitions.isEmpty()) {\n            return Collections.emptyList();\n        }\n\n        List<TopicPartitionOffset> tps = new ArrayList<>();\n        for (KafkaInboundChannelModel.TopicPartition topicPartition : topicPartitions) {\n            String topic = resolveExpressionAsString(topicPartition.getTopic(), \"topicPartitions[].topic\");\n            if (!StringUtils.hasText(topic)) {\n                throw new FlowableIllegalArgumentException(\n                        \"topic in topic partition in channel model [ \" + channelModel.getKey() + \" ] must resolve to a non empty string\");\n            }\n\n            Collection<String> partitions = topicPartition.getPartitions();\n            if (partitions == null || partitions.isEmpty()) {\n                throw new FlowableIllegalArgumentException(\n                        \"partitions in topic partition in channel model [ \" + channelModel.getKey() + \" ] must not be empty\");\n            }\n\n            for (String partition : partitions) {\n                resolvePartitionAsInteger(topic, resolveExpression(partition), tps);\n            }\n\n        }\n\n        return tps;\n    }\n","sourceCodeStart":575,"sourceCodeEnd":611,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java#L575-L611","documentation":"When a channel uses explicit topic partitions, each TopicPartition entry must have a topic that resolves to a non-empty String. resolveTopicPartitions first calls resolveExpressionAsString and then checks StringUtils.hasText; blank or null topics cause FlowableIllegalArgumentException with the channel key in the message.","triggerScenarios":"A topicPartitions[].topic attribute is an expression resolving to null/empty/whitespace String while createKafkaListenerEndpoint processes the channel's topic partition list.","commonSituations":"Placeholder for topic name not set in environment (resolves to empty); topic key left blank in channel model; expression references a property that exists but is empty string; YAML indentation mistake making topic null.","solutions":["Set an actual topic name for each topicPartitions entry, e.g. topic: orders.","Fix the placeholder/environment variable so it resolves to a non-empty value.","Remove the empty topicPartition entry if it is not needed.","Add a startup validation that all referenced placeholders resolve before deploying the model."],"exampleFix":"// before\ntopicPartitions:\n  - topic: ${KAFKA_ORDERS_TOPIC}   # env var unset -> empty\n    partitions: [\"0\"]\n\n// after\ntopicPartitions:\n  - topic: ${KAFKA_ORDERS_TOPIC:orders}\n    partitions: [\"0\"]","handlingStrategy":"validation","validationCode":"for (var tp : channel.getTopicPartitions()) {\n    if (tp.getTopic() == null || tp.getTopic().isBlank())\n        throw new IllegalArgumentException(\"topicPartitions[].topic must be non-empty for channel \" + channel.getKey());\n}","typeGuard":null,"tryCatchPattern":"try { ... } catch (FlowableIllegalArgumentException e) { if (e.getMessage().contains(\"must resolve to a non empty string\")) { log.error(\"Topic partition topic missing: {}\", e.getMessage()); } else throw e; }","preventionTips":["Provide defaults in topic placeholders, e.g. ${TOPIC:orders}","Fail fast on unresolved placeholders (set ignore-unresolvable-placeholders=false)","Validate channel models at deploy time"],"tags":["kafka","validation","topic-partitions","empty-value"],"backgroundTag":"empty-required-field","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"}