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

  1. Configure topicPattern as a plain regex String, e.g. "order-.*".
  2. If a Pattern object is intended, ensure it is java.util.regex.Pattern specifically.
  3. Fix the placeholder to point at a string property, not an object.
  4. 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

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


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)