{"record":{"id":"13d1ff9e245b5108","repo":"apache/pulsar","slug":"when-messageroutingmode-is-custompartition-mes","errorCode":null,"errorMessage":"When 'messageRoutingMode' is CustomPartition, 'messageRouter' should be set","messagePattern":"When 'messageRoutingMode' is CustomPartition, 'messageRouter' should be set","errorType":"exception","errorClass":"PulsarClientException","httpStatus":null,"severity":"error","filePath":"pulsar-client/src/main/java/org/apache/pulsar/client/impl/ProducerBuilderImpl.java","lineNumber":397,"sourceCode":"     * be created.\n     * This method is limited to internal use. This method will only be used when the consumer creates the dlq producer.\n     *\n     * @param initialSubscriptionName Name of the initial subscription of the topic.\n     * @return the producer builder implementation instance\n     */\n    public ProducerBuilderImpl<T> initialSubscriptionName(String initialSubscriptionName) {\n        conf.setInitialSubscriptionName(initialSubscriptionName);\n        return this;\n    }\n\n    private void setMessageRoutingMode() throws PulsarClientException {\n        if (conf.getMessageRoutingMode() == null && conf.getCustomMessageRouter() == null) {\n            messageRoutingMode(MessageRoutingMode.RoundRobinPartition);\n        } else if (conf.getMessageRoutingMode() == null && conf.getCustomMessageRouter() != null) {\n            messageRoutingMode(MessageRoutingMode.CustomPartition);\n        } else if (conf.getMessageRoutingMode() == MessageRoutingMode.CustomPartition\n                && conf.getCustomMessageRouter() == null) {\n            throw new PulsarClientException(\"When 'messageRoutingMode' is \" + MessageRoutingMode.CustomPartition\n                + \", 'messageRouter' should be set\");\n        } else if (conf.getMessageRoutingMode() != MessageRoutingMode.CustomPartition\n                && conf.getCustomMessageRouter() != null) {\n            throw new PulsarClientException(\"When 'messageRouter' is set, 'messageRoutingMode' \"\n                    + \"should be set as \" + MessageRoutingMode.CustomPartition);\n        }\n    }\n\n    @Override\n    public String toString() {\n        return conf != null ? conf.toString() : \"\";\n    }\n}\n","sourceCodeStart":379,"sourceCodeEnd":411,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ProducerBuilderImpl.java#L379-L411","documentation":"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.","triggerScenarios":"Calling ProducerBuilder.messageRoutingMode(MessageRoutingMode.CustomPartition) (or setting the equivalent config property) without also calling messageRouter(...) before create()/createAsync().","commonSituations":"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.","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."],"exampleFix":"// before\nProducer<byte[]> p = client.newProducer().topic(topic)\n    .messageRoutingMode(MessageRoutingMode.CustomPartition).create();\n// after\nProducer<byte[]> p = client.newProducer().topic(topic)\n    .messageRoutingMode(MessageRoutingMode.CustomPartition)\n    .messageRouter(new MyMessageRouter()).create();","handlingStrategy":"validation","validationCode":"if (conf.getMessageRoutingMode() == MessageRoutingMode.CustomPartition && conf.getCustomMessageRouter() == null) {\n    throw new IllegalArgumentException(\"CustomPartition requires messageRouter(...)\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    producer = builder.create();\n} catch (PulsarClientException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"messageRouter\")) {\n        builder.messageRoutingMode(MessageRoutingMode.RoundRobinPartition); // fall back to default routing\n        producer = builder.create();\n    } else throw e;\n}","preventionTips":["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."],"tags":["pulsar","client-configuration","producer","routing"],"backgroundTag":"inconsistent-message-routing-config","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}