iloveeyjafjalla opened a new issue, #11423:
URL: https://github.com/apache/rocketmq/issues/11423

   ### 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 that 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: any (proxy running in LOCAL mode, i.e. embedded in a broker, 
`docs/en/proxy/deploy_guide.md`)
   
   ### RocketMQ version
   
   branch: develop
   Git commit id: a7edeecfb
   
   ### JDK Version
   
   Compiler: Temurin 1.8.0_504 (target 1.8, same as CI)
   
   ### Describe the Bug
   
   `LocalTopicRouteService.getCurrentMessageQueueView` looks the topic up in 
the local broker's topic config table and passes the result straight into the 
route data builder:
   
   ```java
   public MessageQueueView getCurrentMessageQueueView(ProxyContext ctx, String 
topic) throws Exception {
       TopicConfig topicConfig = 
this.brokerController.getTopicConfigManager().getTopicConfigTable().get(topic);
       return new MessageQueueView(topic, toTopicRouteData(topicConfig), null); 
  // topicConfig may be null
   }
   ...
   protected TopicRouteData toTopicRouteData(TopicConfig topicConfig) {
       ...
       queueData.setPerm(topicConfig.getPerm());      // NullPointerException
   ```
   
   
(`proxy/src/main/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteService.java:54-56`,
 NPE at `:83`.) The cluster implementation of the same abstract method answers 
with a proper client error instead — 
`ClusterTopicRouteService.getCurrentMessageQueueView` delegates to 
`getAllMessageQueueView`, and `TopicRouteService.getCacheMessageQueueWrapper` 
throws `new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "No topic route 
info in name server for the topic: " + key)` 
(`TopicRouteService.java:186-194`). That behaviour is even pinned by a test: 
`proxy/src/test/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteServiceTest.java:104`
 asserts `MQClientException` for `getCurrentMessageQueueView(ctx, ERR_TOPIC)`.
   
   **Trigger 1 — a consumer that keeps popping a topic which no longer exists 
(default configuration).** `ConsumerProcessor.popMessage` calls 
`getCurrentMessageQueueView` for the topic carried by the request 
(`proxy/.../processor/ConsumerProcessor.java:96`); a client that still holds an 
assignment after `mqadmin deleteTopic` (or after the topic expired) sends 
exactly that, and instead of the callers' designed `FORBIDDEN, "no readable 
queue"` path it fails with an NPE.
   
   **Trigger 2 — sending to a topic that is not created yet with the type check 
disabled.** `ProducerProcessor.sendMessage` calls the same method 
(`ProducerProcessor.java:88`) after the topic-message-type check; with 
`enableTopicMessageTypeCheck=false` (a supported `ProxyConfig` field, 
`ProxyConfig.java:177`) the check does not run, so a send to a not-yet-created 
topic reaches the NPE and fails with an internal error. (With the default 
`true`, `LocalMetadataService.getTopicMessageType` returns `UNSPECIFIED` and 
`DefaultTopicMessageTypeValidator` rejects the send first, so this trigger 
requires the flag.)
   
   ### Steps to Reproduce
   
   1. Start a proxy in LOCAL mode (embedded in the broker) and let a gRPC 
consumer obtain an assignment for topic `T`.
   2. Delete `T` (`mqadmin deleteTopic -t T`); the consumer keeps popping `T` 
until it refreshes its assignment.
   3. The proxy answers with an internal error and logs 
`java.lang.NullPointerException at 
LocalTopicRouteService.toTopicRouteData(LocalTopicRouteService.java:83)`, 
instead of the `TOPIC_NOT_EXIST` response the cluster mode returns for the same 
situation.
   
   At the unit level the same state is reproduced with the existing harness in 
`LocalTopicRouteServiceTest`: `getCurrentMessageQueueView(ctx, <topic not in 
the broker's topic config table>)` throws NPE today (the existing 
`testGetCurrentMessageQueueView` only covers a topic that was put into the 
table first).
   
   ### What Did You Expect to See?
   
   LOCAL mode reports the same client error its cluster sibling reports, so 
that callers can turn it into a proper response: `MQClientException` with 
`ResponseCode.TOPIC_NOT_EXIST` (and the designed `FORBIDDEN, "no readable 
queue"` / `"no writable queue"` handling stays for topics that exist but have 
no usable queue).
   
   ### What Did You See Instead?
   
   `NullPointerException` while building the route data, surfacing as 
`INTERNAL_SERVER_ERROR`/`SYSTEM_ERROR` with a stack trace in the proxy log, 
which makes a deleted or not-yet-created topic look like a proxy failure rather 
than a missing topic.
   
   ### Additional Context
   
   Minimal fix: mirror the sibling (and `getCacheMessageQueueWrapper`'s 
message) in the LOCAL implementation:
   
   ```java
   if (topicConfig == null) {
       throw new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "No topic 
route info in local broker for the topic: " + topic);
   }
   ```
   
   I will open a PR with that change plus a regression test in 
`LocalTopicRouteServiceTest` (red before: `NullPointerException`; green after: 
`MQClientException` with `TOPIC_NOT_EXIST`).
   


-- 
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]

Reply via email to