apache/kafka · error · java.lang.UnsupportedOperationException

Subscribe to RE2/J pattern is not supported when usingthe %s

Error message

Subscribe to RE2/J pattern is not supported when usingthe %s protocol defined in config %s

What it means

Thrown by ClassicKafkaConsumer.subscribe(SubscriptionPattern, ...) as an UnsupportedOperationException. SubscriptionPattern is the KIP-848 RE2/J-based regex subscription API and is only implemented by the async consumer (group.protocol=consumer). When the classic protocol is selected the method is unsupported by design; the message interpolates GroupProtocol.CLASSIC and ConsumerConfig.GROUP_PROTOCOL_CONFIG so the user knows exactly which config to change. Note the literal source string is missing a space before 'the' ('usingthe'), but the runtime format renders it as-is.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java:542

        }
    }

    @Override
    public void subscribe(Pattern pattern, ConsumerRebalanceListener listener) {
        if (listener == null)
            throw new IllegalArgumentException("RebalanceListener cannot be null");

        subscribeInternal(pattern, Optional.of(listener));
    }

    @Override
    public void subscribe(Pattern pattern) {
        subscribeInternal(pattern, Optional.empty());
    }

    @Override
    public void subscribe(SubscriptionPattern pattern, ConsumerRebalanceListener callback) {
        throw new UnsupportedOperationException(String.format("Subscribe to RE2/J pattern is not supported when using" +
            "the %s protocol defined in config %s", GroupProtocol.CLASSIC, ConsumerConfig.GROUP_PROTOCOL_CONFIG));
    }

    @Override
    public void subscribe(SubscriptionPattern pattern) {
        throw new UnsupportedOperationException(String.format("Subscribe to RE2/J pattern is not supported when using" +
            "the %s protocol defined in config %s", GroupProtocol.CLASSIC, ConsumerConfig.GROUP_PROTOCOL_CONFIG));
    }

    /**
     * Internal helper method for {@link #subscribe(Pattern)} and
     * {@link #subscribe(Pattern, ConsumerRebalanceListener)}
     * <p>
     * Subscribe to all topics matching specified pattern to get dynamically assigned partitions.
     * The pattern matching will be done periodically against all topics existing at the time of check.
     * This can be controlled through the {@code metadata.max.age.ms} configuration: by lowering
     * the max metadata age, the consumer will refresh metadata more often and check for matching topics.
     * <p>

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Set group.protocol=consumer (GroupProtocol.CONSUMER) in the consumer config so the async consumer, which implements SubscriptionPattern, is instantiated.
  2. If you must stay on the classic protocol, use the JDK Pattern overload instead: consumer.subscribe(Pattern.compile("orders\\..*"));
  3. Audit framework adapters (Spring Kafka, Kafka Streams wrappers) that may call SubscriptionPattern and ensure they select the consumer protocol when they do.
  4. Update docs/readmes that reference the RE2/J pattern API to also mandate group.protocol=consumer.

Example fix

// before
props.put(ConsumerConfig.GROUP_PROTOCOL_CONFIG, "classic");
new KafkaConsumer<String,String>(props).subscribe(new SubscriptionPattern("orders\\\\..*"));

// after
props.put(ConsumerConfig.GROUP_PROTOCOL_CONFIG, "consumer");
new KafkaConsumer<String,String>(props).subscribe(new SubscriptionPattern("orders\\\\..*"));
Defensive patterns

Strategy: fallback

Validate before calling

// Detect classic protocol at startup and skip the RE2/J SubscriptionPattern API.
String proto = String.valueOf(props.getOrDefault(
    ConsumerConfig.GROUP_PROTOCOL_CONFIG, GroupProtocol.CLASSIC.name()));
boolean isClassic = GroupProtocol.CLASSIC.name().equalsIgnoreCase(proto);
if (isClassic && pattern instanceof SubscriptionPattern) {
    throw new UnsupportedOperationException(
        "SubscriptionPattern (RE2/J) requires the CONSUMER group protocol; " +
        "use java.util.regex.Pattern with classic consumer, or switch group.protocol.config");
}

Type guard

// Distinguish the two Pattern types at the call boundary.
static boolean isSubscriptionPatternRe2j(Object p) {
    return p instanceof org.apache.kafka.clients.consumer.SubscriptionPattern;
}
// route:
if (isSubscriptionPatternRe2j(pattern)) {
    // only valid on AsyncKafkaConsumer with CONSUMER protocol
} else {
    consumer.subscribe((java.util.regex.Pattern) pattern);
}

Try / catch

try {
    consumer.subscribe(subscriptionPattern, callback);
} catch (UnsupportedOperationException e) {
    if (e.getMessage().contains("RE2/J")) {
        // Fall back to java.util.regex.Pattern overload on classic consumer.
        consumer.subscribe(java.util.regex.Pattern.compile(subscriptionPattern.pattern()), callback);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling consumer.subscribe(new SubscriptionPattern("orders\\..*")) (with or without a callback) on a KafkaConsumer built with group.protocol=classic (the default). Also triggered by frameworks that auto-detect SubscriptionPattern support and call the new API regardless of the configured group protocol.

Common situations: Adopting the RE2/J SubscriptionPattern API from examples/docs without also switching group.protocol to consumer; mixed-protocol code paths where some consumers are classic and others async; library code that calls subscribe(SubscriptionPattern) unconditionally; upgrading the client jar and picking up the new API surface before updating config.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/09b229f76ad0ebbb.json. Report an issue: GitHub.