unbridled-41 opened a new issue, #10990: URL: https://github.com/apache/rocketmq/issues/10990
### Before Creating the Bug Report - [x] I found a bug, not just asking a question, which should be created in [GitHub Discussions](https://github.com/apache/rocketmq/discussions). - [x] I have searched the [GitHub Issues](https://github.com/apache/rocketmq/issues) and [GitHub Discussions](https://github.com/apache/rocketmq/discussions) of this repository and believe this is not a duplicate. - [x] I have confirmed that this bug belongs to the current repository, not other repositories of RocketMQ. ### Runtime platform environment - OS: Linux - Component: Broker (`PopLongPollingService` + `DefaultMessageStore.ReputMessageService`) ### RocketMQ version - branch: develop - Git commit id: e348efa66 ### JDK Version JDK 8 ### Describe the Bug `PopLongPollingService#notifyMessageArrivingFromRetry` dereferences the dispatch request's property map without a null check: ```java private void notifyMessageArrivingFromRetry(String topic, int queueId, Long tagsCode, long msgStoreTime, byte[] filterBitMap, Map<String, String> properties) { String prefix = MixAll.RETRY_GROUP_TOPIC_PREFIX; String originGroup = properties.get(MessageConst.PROPERTY_ORIGIN_GROUP); // NPE when properties == null ``` A `DispatchRequest` legitimately carries a null properties map: `MessageDecoder.string2messageProperties` returns null for a message stored without properties (e.g. a message written by a non-Java client, or through any path that stores a message on a `%RETRY%`-prefixed topic without user properties). The store's own code acknowledges this — `DefaultMessageStore#notifyMessageArrive4MultiQueue` explicitly guards `prop == null`, and `PullRequestHoldService#notifyMessageArriving` guards `properties != null` — but the pop retry branch does not. Why this is severe: the listener is invoked from `DefaultMessageStore.ReputMessageService#doReput` **before** `reputFromOffset` is advanced, and `doReput` only catches `RocksDBException`. The resulting `NullPointerException` propagates to `ServiceThread.run`, which logs and loops — then re-reads the **same** commitlog record and throws again, forever. The broker stops dispatching *all* messages (consume queues stop advancing, no long-polling wakeups, consumers see a full outage) while flooding the log at ~1000 lines/s. A single poison message is enough; it stays poisoned across restarts because `reputFromOffset` is recovered from the consume queue state. ### Steps to Reproduce 1. On a broker with pop enabled, store a message with no properties on a topic named `%RETRY%<group>` (any client able to write that topic; the properties map in the dispatch request is then null). 2. Watch the reput thread loop on `service has exception. NullPointerException` at `PopLongPollingService.notifyMessageArrivingFromRetry`, with `reputFromOffset` frozen. In a unit test, calling `notifyMessageArrivingWithRetryTopic("%RETRY%g", -1, -1, -1L, 0L, null, null)` throws NPE on current develop. ### What Did You Expect to See? The notification is skipped (there is no origin group to wake up), and dispatch continues. ### What Did You See Instead? NPE in the reput thread → the same message is re-dispatched forever → broker-wide dispatch stall. ### Additional Context Fix: return early when `properties == null` (a retry topic message without properties can't be mapped back to an origin group, so there is nothing to wake up), consistent with the existing guards in `PullRequestHoldService` and `notifyMessageArrive4MultiQueue`. I will submit a PR with a regression test. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
