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

  1. Add explicit partition entries, e.g. partitions: ["0", "1"].
  2. Remove the topicPartitions entry and use plain topics/topicPattern if all partitions are wanted.
  3. Fix the expression producing the partitions collection so it yields a non-empty list.
  4. 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

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


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)