{"record":{"id":"3012097bbbbdc335","repo":"flowable/flowable-engine","slug":"partitions-in-topic-partition-in-channel-model","errorCode":null,"errorMessage":"partitions in topic partition in channel model [ <channelModel.getKey()> ] must not be empty","messagePattern":"partitions in topic partition in channel model \\[ <channelModel\\.getKey\\(\\)> \\] must not be empty","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":599,"sourceCode":"    }\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\n    protected void resolvePartitionAsInteger(String topic, Object resolvedValue, List<TopicPartitionOffset> result) {\n        // This is the same as it is done in the Spring KafkaListenerAnnotationBeanPostProcessor#resolvePartitionAsInteger\n\n        if (resolvedValue instanceof String[]) {\n            for (Object object : (String[]) resolvedValue) {\n                resolvePartitionAsInteger(topic, object, result);","sourceCodeStart":581,"sourceCodeEnd":617,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java#L581-L617","documentation":"Each topicPartitions entry must declare at least one partition. After validating the topic name, resolveTopicPartitions checks that partitions is non-null and non-empty; otherwise FlowableIllegalArgumentException is thrown including the channel key. Partitions are then resolved per entry via resolvePartitionAsInteger.","triggerScenarios":"A topicPartitions entry in the Kafka inbound channel model has an empty or missing partitions collection while createKafkaListenerEndpoint resolves the topic partition list.","commonSituations":"Channel model authored without partitions key; partitions: [] after filtering by an env-driven expression; model generator omitted partitions; user assumed partitions are auto-discovered when explicitly listed.","solutions":["Add explicit partition entries, e.g. partitions: [\"0\", \"1\"].","Remove the topicPartitions entry and use plain topics/topicPattern if all partitions are wanted.","Fix the expression producing the partitions collection so it yields a non-empty list.","Verify model JSON/YAML key spelling (partitions) and that no default filtering empties the list."],"exampleFix":"// before\ntopicPartitions:\n  - topic: orders\n    partitions: []\n\n// after\ntopicPartitions:\n  - topic: orders\n    partitions: [\"0\", \"1\"]","handlingStrategy":"validation","validationCode":"for (var tp : channel.getTopicPartitions()) {\n    if (tp.getPartitions() == null || tp.getPartitions().isEmpty())\n        throw new IllegalArgumentException(\"partitions must not be empty for topic \" + tp.getTopic());\n}","typeGuard":null,"tryCatchPattern":"try { ... } catch (FlowableIllegalArgumentException e) { if (e.getMessage().contains(\"must not be empty\")) { log.error(\"Topic partitions missing: {}\", e.getMessage()); } else throw e; }","preventionTips":["Always include at least one partition per topicPartitions entry","Use plain topics/topicPattern if all partitions should be consumed","Validate partition lists against actual broker partition counts in tests"],"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"}