{"record":{"id":"9c687c299c4cd7f7","repo":"apache/pulsar","slug":"use-choosepartition-message-topicmetadata-inste","errorCode":null,"errorMessage":"Use #choosePartition(Message, TopicMetadata) instead","messagePattern":"Use #choosePartition\\(Message, TopicMetadata\\) instead","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"pulsar-client-api/src/main/java/org/apache/pulsar/client/api/MessageRouter.java","lineNumber":45,"sourceCode":" * to a producer to select the partition that a particular\n * messsage should be published on.\n *\n * @see ProducerBuilder#messageRouter(MessageRouter)\n */\n@InterfaceAudience.Public\n@InterfaceStability.Stable\npublic interface MessageRouter extends Serializable {\n\n    /**\n     *\n     * @param msg\n     *            Message object\n     * @return The index of the partition to use for the message\n     * @deprecated since 1.22.0. Please use {@link #choosePartition(Message, TopicMetadata)} instead.\n     */\n    @Deprecated\n    default int choosePartition(Message<?> msg) {\n        throw new UnsupportedOperationException(\"Use #choosePartition(Message, TopicMetadata) instead\");\n    }\n\n    /**\n     * Choose a partition based on msg and the topic metadata.\n     *\n     * @param msg message to route\n     * @param metadata topic metadata\n     * @return the partition to route the message.\n     * @since 1.22.0\n     */\n    default int choosePartition(Message<?> msg, TopicMetadata metadata) {\n        return choosePartition(msg);\n    }\n\n}\n","sourceCodeStart":27,"sourceCodeEnd":61,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-api/src/main/java/org/apache/pulsar/client/api/MessageRouter.java#L27-L61","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nclass MyRouter implements MessageRouter {\n    @Override\n    public int choosePartition(Message<?> msg) { return hash(msg) % 3; }\n}\n// after\nclass MyRouter implements MessageRouter {\n    @Override\n    public int choosePartition(Message<?> msg, TopicMetadata metadata) {\n        return hash(msg) % metadata.numPartitions();\n    }\n}","handlingStrategy":"type-guard","validationCode":"// Fail fast in tests: routers must implement the metadata-aware overload\nstatic void checkRouter(MessageRouter router) {\n    if (!Arrays.stream(router.getClass().getMethods())\n            .anyMatch(m -> m.getName().equals(\"choosePartition\")\n                && m.getParameterCount() == 2))\n        throw new IllegalStateException(\"Router must implement choosePartition(Message, TopicMetadata)\");\n}","typeGuard":"static boolean supportsMetadataRouting(MessageRouter router) {\n    try {\n        router.getClass().getMethod(\"choosePartition\", Message.class, TopicMetadata.class);\n        return true;\n    } catch (NoSuchMethodException e) { return false; }\n}","tryCatchPattern":"try {\n    int partition = router.choosePartition(msg);\n} catch (UnsupportedOperationException e) {\n    // deprecated overload not implemented — migrate call site to choosePartition(msg, metadata)\n}","preventionTips":["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."],"tags":["deprecated-api","message-router","unsupported-operation","partitioning"],"backgroundTag":"deprecated-method-not-implemented","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"}