apache/pulsar · error · UnsupportedOperationException
Use #choosePartition(Message, TopicMetadata) instead
Error message
Use #choosePartition(Message, TopicMetadata) instead
What it means
The single-argument MessageRouter.choosePartition(Message) default method is deprecated and its default implementation deliberately throws UnsupportedOperationException to force routers to migrate to choosePartition(Message, TopicMetadata). If a custom router does not override either method (or caller code invokes the old overload on a router that only inherits the default), this error is thrown at produce time.
Source
Thrown at pulsar-client-api/src/main/java/org/apache/pulsar/client/api/MessageRouter.java:45
* to a producer to select the partition that a particular
* messsage should be published on.
*
* @see ProducerBuilder#messageRouter(MessageRouter)
*/
@InterfaceAudience.Public
@InterfaceStability.Stable
public interface MessageRouter extends Serializable {
/**
*
* @param msg
* Message object
* @return The index of the partition to use for the message
* @deprecated since 1.22.0. Please use {@link #choosePartition(Message, TopicMetadata)} instead.
*/
@Deprecated
default int choosePartition(Message<?> msg) {
throw new UnsupportedOperationException("Use #choosePartition(Message, TopicMetadata) instead");
}
/**
* Choose a partition based on msg and the topic metadata.
*
* @param msg message to route
* @param metadata topic metadata
* @return the partition to route the message.
* @since 1.22.0
*/
default int choosePartition(Message<?> msg, TopicMetadata metadata) {
return choosePartition(msg);
}
}
View on GitHub (pinned to 820761864e)
Solutions
- Implement choosePartition(Message<?>, TopicMetadata) in your custom router and use topicMetadata.numPartitions() instead of hardcoding the partition count.
- If you maintain a wrapper, forward the deprecated call: return choosePartition(msg, TopicMetadata.INVALID).
- Remove any direct call sites that invoke the one-argument overload; always route through the metadata-aware API.
Example fix
// before
class MyRouter implements MessageRouter {
@Override
public int choosePartition(Message<?> msg) { return hash(msg) % 3; }
}
// after
class MyRouter implements MessageRouter {
@Override
public int choosePartition(Message<?> msg, TopicMetadata metadata) {
return hash(msg) % metadata.numPartitions();
}
} Defensive patterns
Strategy: type-guard
Validate before calling
// Fail fast in tests: routers must implement the metadata-aware overload
static void checkRouter(MessageRouter router) {
if (!Arrays.stream(router.getClass().getMethods())
.anyMatch(m -> m.getName().equals("choosePartition")
&& m.getParameterCount() == 2))
throw new IllegalStateException("Router must implement choosePartition(Message, TopicMetadata)");
} Type guard
static boolean supportsMetadataRouting(MessageRouter router) {
try {
router.getClass().getMethod("choosePartition", Message.class, TopicMetadata.class);
return true;
} catch (NoSuchMethodException e) { return false; }
} Try / catch
try {
int partition = router.choosePartition(msg);
} catch (UnsupportedOperationException e) {
// deprecated overload not implemented — migrate call site to choosePartition(msg, metadata)
} Prevention
- Always implement choosePartition(Message<?>, TopicMetadata) in custom routers; never rely on the deprecated overload.
- Use topicMetadata.numPartitions() instead of a hardcoded partition count.
- Add a compile-time lint or test that greps router classes for the one-argument override.
When it happens
Trigger: Implementing a custom MessageRouter that overrides nothing (or only the deprecated overload) and then calling router.choosePartition(msg) directly, or producing with a ClientBuilder-level router whose only override is the deprecated method on a code path that never delegates.
Common situations: Upgrading from pre-1.22 code where the single-arg method was the contract; tutorials copied from old blog posts; a router class left abstract over the new signature after the API migration.
Related errors
- Method not implemented!
- BookKeeper client is not available
- Package Management Service is not enabled in the broker.
- Expire message by timestamp is not supported for non-persist
- Expire message by position is not supported for non-persiste
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/9c687c299c4cd7f7.
Report an issue: GitHub.