flowable/flowable-engine · error · IllegalStateException
topicPattern in channel model
Error message
topicPattern in channel model [ <channelModel> ] must resolve to a Pattern or String, not <class>
What it means
resolvePattern resolves the topicPattern attribute of a Kafka inbound channel; the expression may resolve to a String (compiled via Pattern.compile) or a java.util.regex.Pattern, or null. Any other resolved type throws IllegalStateException. This guards regex-based topic subscription configuration.
Solutions
- Configure topicPattern as a plain regex String, e.g. "order-.*".
- If a Pattern object is intended, ensure it is java.util.regex.Pattern specifically.
- Fix the placeholder to point at a string property, not an object.
- Validate the regex compiles (also avoids PatternSyntaxException downstream).
Example fix
// before
topicPattern: ${compiledPatternBean} // not java.util.regex.Pattern
// after
topicPattern: "order-.*" Defensive patterns
Strategy: type-guard
Validate before calling
Object resolved = resolveExpression(topicPattern);
if (resolved != null && !(resolved instanceof String) && !(resolved instanceof java.util.regex.Pattern))
throw new IllegalArgumentException("topicPattern must be a String or java.util.regex.Pattern"); Type guard
boolean isPatternLike(Object v) { return v == null || v instanceof String || v instanceof java.util.regex.Pattern; } Try / catch
try { ... } catch (IllegalStateException e) { if (e.getMessage().contains("must resolve to a Pattern or String")) { log.error("topicPattern wrong type: {}", e.getMessage()); } else throw e; } Prevention
- Configure topicPattern as a regex String
- If passing Pattern objects, ensure they are java.util.regex.Pattern
- Compile-check the regex in unit tests
When it happens
Trigger: The channel's topicPattern attribute resolves (via expression/placeholder) to an object that is neither String, Pattern, nor null when createKafkaListenerEndpoint builds the listener.
Common situations: topicPattern points to a precompiled Pattern from a different regex library (e.g. scala.util.matching.Regex or Spring's PathPattern); a config property bound as a compiled object; expression returning a Character[].
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- The [ ] must resolve to a Boolean or a String that can be…
- The [ ] must resolve to a String. Resolved to [ ] for [ ]
- The [ ] must resolve to an Number or a String that can be…
- The [ ] must resolve to an Number or a String that can be…
- Channel definition cannot resolve as a String[] or a String
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/d59f6c78a53546e2.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java:575
resolveTopics(object, result, channelDefinition);
}
} else {
throw new IllegalArgumentException(
"Channel definition " + channelDefinition + " cannot resolve " + resolvedValue + " as a String[] or a String");
}
}
protected Pattern resolvePattern(KafkaInboundChannelModel channelModel) {
Pattern pattern = null;
String topicPattern = channelModel.getTopicPattern();
if (StringUtils.hasText(topicPattern)) {
Object resolved = resolveExpression(topicPattern);
if (resolved instanceof String) {
pattern = Pattern.compile((String) resolved);
} else if (resolved instanceof Pattern) {
pattern = (Pattern) resolved;
} else if (resolved != null) {
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(View on GitHub (pinned to d6d39ce1c6)