ymwneu opened a new issue, #11215: URL: https://github.com/apache/rocketmq/issues/11215
### 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 centos ### RocketMQ version 5.5.1 ### JDK Version jdk 8 ### Describe the Bug When a consumer using CONSUME_FROM_LAST_OFFSET starts on a brand-new topic/queue that has no stored consumer offset, the broker can permanently skip the very first message (offset 0). QUERY_CONSUMER_OFFSET initializes the start offset only when the first message is already in the page cache: the condition is roughly minOffset <= 0 && checkInMemByConsumeOffset(topic, queueId, 0, 1). On a freshly created, still-empty queue offset 0 is not yet in memory, so the broker returns QUERY_NOT_FOUND. The client then falls back to a separate GET_MAX_OFFSET request to decide where to start. These two requests are not atomic: if a producer appends the first message in between, GET_MAX_OFFSET now returns 1, the consumer pins its start offset at 1, and the message at offset 0 is never consumed. The same checkInMemByConsumeOffset-only logic (and therefore the same race) also exists in PopMessageProcessor#getInitOffset and BroadcastOffsetManager#getOffset. ### Steps to Reproduce 1. Create a brand-new topic/queue with no committed consumer offset. 2. Start a consumer group configured with CONSUME_FROM_LAST_OFFSET and let it issue QUERY_CONSUMER_OFFSET while the queue is still empty (broker replies QUERY_NOT_FOUND). 3. Immediately after that reply — before the client's follow-up GET_MAX_OFFSET lands — have a producer send exactly one message (it becomes offset 0, max offset becomes 1). 4. Let the consumer complete its GET_MAX_OFFSET fallback and begin consuming. To make the timing window easy to hit, insert a short delay between the client's QUERY_CONSUMER_OFFSET and GET_MAX_OFFSET, and send the first message during that delay. ### What Did You Expect to See? The consumer starts at offset 0 and receives the first message. For a brand-new queue with no stored offset, "consume from last offset" should resolve to offset 0 (the last offset of an empty queue is 0), so the first message that arrives is delivered rather than skipped. ### What Did You See Instead? The consumer's start offset is pinned at 1 and the message at offset 0 is skipped forever. Because the offset is then committed at 1, the message is never redelivered — it is silently lost from that consumer group's perspective. ### Additional Context _No response_ -- 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]
