apache/rocketmq · error · MQClientException

208

208

Error message

query message by id finished, but no message.

What it means

Thrown by MQAdminImpl.viewMessage(topic, msgId) with response code NO_MESSAGE (208) when MessageDecoder.decodeMessageId(msgId) fails to parse the string into a MessageId (broker address + offset). Despite the wording, this is a malformed-msgId parse failure on the client, not a broker query that came back empty — the decode exception is swallowed and this MQClientException is raised instead.

Source

Thrown at client/src/main/java/org/apache/rocketmq/client/impl/MQAdminImpl.java:273

        if (brokerAddr != null) {
            try {
                return this.mQClientFactory.getMQClientAPIImpl().getEarliestMsgStoretime(brokerAddr, mq, timeoutMillis);
            } catch (Exception e) {
                throw new MQClientException("Invoke Broker[" + brokerAddr + "] exception", e);
            }
        }

        throw new MQClientException("The broker[" + mq.getBrokerName() + "] not exist", null);
    }

    public MessageExt viewMessage(String topic, String msgId)
        throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
        MessageId messageId;
        try {
            messageId = MessageDecoder.decodeMessageId(msgId);
        } catch (Exception e) {
            throw new MQClientException(ResponseCode.NO_MESSAGE, "query message by id finished, but no message.");
        }
        return this.mQClientFactory.getMQClientAPIImpl().viewMessage(NetworkUtil.socketAddress2String(messageId.getAddress()),
            topic, messageId.getOffset(), timeoutMillis);
    }

    public QueryResult queryMessage(String topic, String key, int maxNum, long begin,
        long end) throws MQClientException,
        InterruptedException {
        return queryMessage(null, topic, key, maxNum, begin, end, false, MessageConst.INDEX_KEY_TYPE, null);
    }

    public QueryResult queryMessageByUniqKey(String topic, String uniqKey, int maxNum, long begin, long end)
        throws MQClientException, InterruptedException {
        return queryMessage(null, topic, uniqKey, maxNum, begin, end, true, MessageConst.INDEX_UNIQUE_TYPE, null);
    }

    public QueryResult queryMessageByUniqKey(String clusterName, String topic, String uniqKey, int maxNum, long begin,
        long end)

View on GitHub (pinned to 293f588571)

Solutions

  1. Ensure msgId is a valid offset message id obtained from SendResult.getMsgId() or MessageExt.getMsgId() from the same client version
  2. To look up by unique key instead, use queryMessageByUniqKey(topic, uniqKey, ...) which queries the index
  3. If ids come from a newer producer, upgrade the client jar so decodeMessageId understands the id format
  4. Validate format before calling: 32 hex chars (or 64 with total-length field) for the installed client version
  5. Check for whitespace/linebreaks accidentally included when ids are copied from logs

Example fix

// before: uniqKey mistaken for msgId
MessageExt msg = adminExt.viewMessage("T", "user-order-12345"); // decode fails -> 208

// after: query by unique key
QueryResult r = adminExt.queryMessageByUniqKey("T", "user-order-12345", 1, 0, Long.MAX_VALUE);
MessageExt msg = r.getMessageList().get(0);
Defensive patterns

Strategy: validation

Validate before calling

private static final Pattern MSG_ID = Pattern.compile("^[0-9a-fA-F]{32,64}$");
boolean isOffsetMsgId(String s) { return s != null && MSG_ID.matcher(s).matches(); }

if (isOffsetMsgId(msgId)) { adminExt.viewMessage(topic, msgId); }
else { adminExt.queryMessageByUniqKey(topic, msgId, 1, 0, Long.MAX_VALUE); }

Try / catch

try {
    MessageExt m = adminExt.viewMessage(topic, msgId);
} catch (MQClientException e) {
    if (e.getResponseCode() == ResponseCode.NO_MESSAGE) {
        // msgId unparseable: fall back to uniq-key query
    } else throw e;
}

Prevention

When it happens

Trigger: Calling viewMessage(topic, msgId) with a string that is not a valid RocketMQ offset message id: wrong length, non-hex characters, null, or passing a business uniqKey (like a KEY property or generated UUID) where the 32-char offset msgId is required. Client-side only: the broker is never contacted when this fires.

Common situations: Passing SendResult.getMsgId() from a NEW API version into an OLD client whose decodeMessageId expects the total-length header (version incompatibility); confusing the unique key with the message id; truncated ids from logs or user input.

Related errors


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