flowable/flowable-engine · error · FlowableIllegalArgumentException
topic in topic partition in channel model […
Error message
topic in topic partition in channel model [ <channelModel.getKey()> ] must resolve to a non empty string
What it means
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.
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.
Example fix
// before
topicPartitions:
- topic: ${KAFKA_ORDERS_TOPIC} # env var unset -> empty
partitions: ["0"]
// after
topicPartitions:
- topic: ${KAFKA_ORDERS_TOPIC:orders}
partitions: ["0"] Defensive patterns
Strategy: validation
Validate before calling
for (var tp : channel.getTopicPartitions()) {
if (tp.getTopic() == null || tp.getTopic().isBlank())
throw new IllegalArgumentException("topicPartitions[].topic must be non-empty for channel " + channel.getKey());
} Try / catch
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; } Prevention
- 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
When it happens
Trigger: A topicPartitions[].topic attribute is an expression resolving to null/empty/whitespace String while createKafkaListenerEndpoint processes the channel's topic partition list.
Common situations: 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.
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
- partitions 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/4f1d5980c9a50dc1.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java:593
throw new IllegalStateException(
"topicPattern in channel model [ " + channelModel + " ] must resolve to a Pattern or String, not " + resolved.getClass());
}
}
return pattern;
}
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;
}
View on GitHub (pinned to d6d39ce1c6)