apache/rocketmq · error · RemotingCommandException

Failed to get max consume offset

Error message

Failed to get max consume offset

What it means

ChangeInvisibleTimeProcessor (pop consumer ack-delay extension) validates the pop offset: it reads MessageStore.getMaxOffsetInQueue for the topic/queue and wraps any ConsumeQueueException in RemotingCommandException, failing the CHANGE_INVISIBLE_TIME request.

Source

Thrown at broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java:134

            String errorInfo = String.format("queueId[%d] is illegal, topic:[%s] topicConfig.readQueueNums:[%d] consumer:[%s]",
                requestHeader.getQueueId(), requestHeader.getTopic(), topicConfig.getReadQueueNums(), channel.remoteAddress());
            POP_LOGGER.warn(errorInfo);
            response.setCode(ResponseCode.MESSAGE_ILLEGAL);
            response.setRemark(errorInfo);
            return CompletableFuture.completedFuture(response);
        }

        CompletableFuture<RemotingCommand> future = processChangeInvisibleTimeForLite(requestHeader, response, responseHeader);
        if (future != null) {
            return future;
        }

        long minOffset = this.brokerController.getMessageStore().getMinOffsetInQueue(requestHeader.getTopic(), requestHeader.getQueueId());
        long maxOffset;
        try {
            maxOffset = this.brokerController.getMessageStore().getMaxOffsetInQueue(requestHeader.getTopic(), requestHeader.getQueueId());
        } catch (ConsumeQueueException e) {
            throw new RemotingCommandException("Failed to get max consume offset", e);
        }
        if (requestHeader.getOffset() < minOffset || requestHeader.getOffset() >= maxOffset) {
            response.setCode(ResponseCode.NO_MESSAGE);
            return CompletableFuture.completedFuture(response);
        }

        String[] extraInfo = ExtraInfoUtil.split(requestHeader.getExtraInfo());
        if (brokerController.getBrokerConfig().isPopConsumerKVServiceEnable()) {
            if (ExtraInfoUtil.isOrder(extraInfo)) {
                return this.processChangeInvisibleTimeForOrderNew(
                    requestHeader, extraInfo, response, responseHeader);
            }
            try {
                long current = System.currentTimeMillis();
                brokerController.getPopConsumerService().changeInvisibilityDuration(
                    ExtraInfoUtil.getPopTime(extraInfo), ExtraInfoUtil.getInvisibleTime(extraInfo), current,
                    requestHeader.getInvisibleTime(), requestHeader.getConsumerGroup(), requestHeader.getTopic(),
                    requestHeader.getQueueId(), requestHeader.getOffset(), requestHeader.isSuspend());

View on GitHub (pinned to 293f588571)

Solutions

  1. Check broker.log for the underlying ConsumeQueueException and failing topic/queueId.
  2. Ensure the topic still exists and its consume queues are healthy (mqAdmin topicStatus).
  3. Retry after the broker finishes loading; if queues are corrupt, restore/rebuild them.
  4. Avoid issuing changeInvisibleTime for messages whose topic has been deleted.
Defensive patterns

Strategy: retry

Try / catch

catch (RemotingCommandException e) { if (e.getCause() instanceof ConsumeQueueException) { scheduleChangeInvisibleTimeRetryWithBackoff(); return; } throw e; }

Prevention

When it happens

Trigger: Pop consumer calls ChangeInvisibleTime for a message whose consume queue cannot be read — corrupt queue files, store still loading, RocksDB consume queue failure, or topic deleted while pop requests are in flight.

Common situations: Long pop-invisible-time messages being extended after the topic was deleted/recreated; broker recovered with damaged consume queues; store not fully initialized at request time.

Related errors


AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14). Data as JSON: /api/errors/a5869dd687d19167. Report an issue: GitHub.