apache/pulsar · error · PulsarClientException
When 'messageRoutingMode' is CustomPartition, 'messageRouter
Error message
When 'messageRoutingMode' is CustomPartition, 'messageRouter' should be set
What it means
Thrown by ProducerBuilderImpl.setMessageRoutingMode when the producer configuration sets messageRoutingMode to CustomPartition but supplies no custom MessageRouter. CustomPartition routing means partitions are dispatched by a user-provided router, so without one the mode is meaningless and the client refuses to create the producer.
Source
Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/ProducerBuilderImpl.java:397
* be created.
* This method is limited to internal use. This method will only be used when the consumer creates the dlq producer.
*
* @param initialSubscriptionName Name of the initial subscription of the topic.
* @return the producer builder implementation instance
*/
public ProducerBuilderImpl<T> initialSubscriptionName(String initialSubscriptionName) {
conf.setInitialSubscriptionName(initialSubscriptionName);
return this;
}
private void setMessageRoutingMode() throws PulsarClientException {
if (conf.getMessageRoutingMode() == null && conf.getCustomMessageRouter() == null) {
messageRoutingMode(MessageRoutingMode.RoundRobinPartition);
} else if (conf.getMessageRoutingMode() == null && conf.getCustomMessageRouter() != null) {
messageRoutingMode(MessageRoutingMode.CustomPartition);
} else if (conf.getMessageRoutingMode() == MessageRoutingMode.CustomPartition
&& conf.getCustomMessageRouter() == null) {
throw new PulsarClientException("When 'messageRoutingMode' is " + MessageRoutingMode.CustomPartition
+ ", 'messageRouter' should be set");
} else if (conf.getMessageRoutingMode() != MessageRoutingMode.CustomPartition
&& conf.getCustomMessageRouter() != null) {
throw new PulsarClientException("When 'messageRouter' is set, 'messageRoutingMode' "
+ "should be set as " + MessageRoutingMode.CustomPartition);
}
}
@Override
public String toString() {
return conf != null ? conf.toString() : "";
}
}
View on GitHub (pinned to 820761864e)
Solutions
- Call producerBuilder.messageRouter(myMessageRouter) whenever the routing mode is CustomPartition.
- Alternatively drop the CustomPartition setting and use the default RoundRobinPartition routing.
- If the mode comes from external config, validate that the router is present in the same place the mode is set.
Example fix
// before
Producer<byte[]> p = client.newProducer().topic(topic)
.messageRoutingMode(MessageRoutingMode.CustomPartition).create();
// after
Producer<byte[]> p = client.newProducer().topic(topic)
.messageRoutingMode(MessageRoutingMode.CustomPartition)
.messageRouter(new MyMessageRouter()).create(); Defensive patterns
Strategy: validation
Validate before calling
if (conf.getMessageRoutingMode() == MessageRoutingMode.CustomPartition && conf.getCustomMessageRouter() == null) {
throw new IllegalArgumentException("CustomPartition requires messageRouter(...)");
} Try / catch
try {
producer = builder.create();
} catch (PulsarClientException e) {
if (e.getMessage() != null && e.getMessage().contains("messageRouter")) {
builder.messageRoutingMode(MessageRoutingMode.RoundRobinPartition); // fall back to default routing
producer = builder.create();
} else throw e;
} Prevention
- Always pair messageRoutingMode(CustomPartition) with messageRouter(...) in builder helpers.
- Centralize producer config assembly so mode and router are validated together.
- Add unit tests asserting producer creation fails fast on inconsistent routing config.
When it happens
Trigger: Calling ProducerBuilder.messageRoutingMode(MessageRoutingMode.CustomPartition) (or setting the equivalent config property) without also calling messageRouter(...) before create()/createAsync().
Common situations: Copy-pasting a config that mentions CustomPartition; building config programmatically where the router is set conditionally; migrating code that previously set a router via a different config field; YAML/properties-based config where the router object cannot be expressed.
Related errors
- When 'messageRouter' is set, 'messageRoutingMode' should be
- Invalid client configuration
- Both externalExecutorProvider and internalExecutorProvider m
- ${cause.getMessage()}
- ${cause}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/13d1ff9e245b5108.
Report an issue: GitHub.