flowable/flowable-engine · error · FlowableIllegalArgumentException
partitions in topic partition in channel model […
Error message
partitions in topic partition in channel model [ <channelModel.getKey()> ] must not be empty
What it means
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.
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.
Example fix
// before
topicPartitions:
- topic: orders
partitions: []
// after
topicPartitions:
- topic: orders
partitions: ["0", "1"] Defensive patterns
Strategy: validation
Validate before calling
for (var tp : channel.getTopicPartitions()) {
if (tp.getPartitions() == null || tp.getPartitions().isEmpty())
throw new IllegalArgumentException("partitions must not be empty for topic " + tp.getTopic());
} Try / catch
try { ... } catch (FlowableIllegalArgumentException e) { if (e.getMessage().contains("must not be empty")) { log.error("Topic partitions missing: {}", e.getMessage()); } else throw e; } Prevention
- 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
When it happens
Trigger: A topicPartitions entry in the Kafka inbound channel model has an empty or missing partitions collection while createKafkaListenerEndpoint resolves the topic partition list.
Common situations: 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.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- topic in topic partition in channel model […
- Channel definition cannot resolve as a String[] or a String
- The channel json key detection value was not found for the…
- The channel xml key detection value was not found for the…
- A channel key detection value is required for the channel…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/3012097bbbbdc335.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java:599
}
protected Collection<TopicPartitionOffset> resolveTopicPartitions(KafkaInboundChannelModel channelModel) {
Collection<KafkaInboundChannelModel.TopicPartition> topicPartitions = channelModel.getTopicPartitions();
if (topicPartitions == null || topicPartitions.isEmpty()) {
return Collections.emptyList();
}
List<TopicPartitionOffset> tps = new ArrayList<>();
for (KafkaInboundChannelModel.TopicPartition topicPartition : topicPartitions) {
String topic = resolveExpressionAsString(topicPartition.getTopic(), "topicPartitions[].topic");
if (!StringUtils.hasText(topic)) {
throw new FlowableIllegalArgumentException(
"topic in topic partition in channel model [ " + channelModel.getKey() + " ] must resolve to a non empty string");
}
Collection<String> partitions = topicPartition.getPartitions();
if (partitions == null || partitions.isEmpty()) {
throw new FlowableIllegalArgumentException(
"partitions in topic partition in channel model [ " + channelModel.getKey() + " ] must not be empty");
}
for (String partition : partitions) {
resolvePartitionAsInteger(topic, resolveExpression(partition), tps);
}
}
return tps;
}
protected void resolvePartitionAsInteger(String topic, Object resolvedValue, List<TopicPartitionOffset> result) {
// This is the same as it is done in the Spring KafkaListenerAnnotationBeanPostProcessor#resolvePartitionAsInteger
if (resolvedValue instanceof String[]) {
for (Object object : (String[]) resolvedValue) {
resolvePartitionAsInteger(topic, object, result);View on GitHub (pinned to d6d39ce1c6)