louislam/uptime-kuma · error · Error

Message Mismatch - Topic: ${monitor.mqttTopic}; Message: ${r

Error message

Message Mismatch - Topic: ${monitor.mqttTopic}; Message: ${receivedMessage}

What it means

Thrown by MqttMonitorType.checkKeyword after the broker delivered a message whose payload does not contain the configured success keyword (monitor.mqttSuccessMessage). It also fires when receivedMessage is null, so both 'no payload' and 'wrong payload' surface as the same error. The check is a substring .includes() test, so it is case- and whitespace-sensitive.

Source

Thrown at server/monitor-types/mqtt.js:66

            throw new Error("Unknown MQTT Check Type");
        }
    }

    /**
     * Check using keyword matching
     * @param {object} monitor Monitor object
     * @param {object} heartbeat Heartbeat object
     * @param {string} messageTopic Received MQTT topic
     * @param {string} receivedMessage Received MQTT message
     * @returns {void}
     * @throws {Error} If keyword is not found in message
     */
    checkKeyword(monitor, heartbeat, messageTopic, receivedMessage) {
        if (receivedMessage != null && receivedMessage.includes(monitor.mqttSuccessMessage)) {
            heartbeat.msg = `Topic: ${messageTopic}; Message: ${receivedMessage}`;
            heartbeat.status = UP;
        } else {
            throw new Error(`Message Mismatch - Topic: ${monitor.mqttTopic}; Message: ${receivedMessage}`);
        }
    }

    /**
     * Check using JSONata query
     * @param {object} monitor Monitor object
     * @param {object} heartbeat Heartbeat object
     * @param {string} receivedMessage Received MQTT message
     * @returns {Promise<void>}
     */
    async checkJsonQuery(monitor, heartbeat, receivedMessage) {
        const parsedMessage = JSON.parse(receivedMessage);
        const expression = jsonata(monitor.jsonPath);
        const result = await expression.evaluate(parsedMessage);

        if (result?.toString() === monitor.expectedValue) {
            heartbeat.msg = "Message received, expected value is found";
            heartbeat.status = UP;

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Confirm the exact bytes the publisher sends (e.g. mosquitto_sub -t '<topic>') and paste a unique substring of that payload into mqttSuccessMessage.
  2. If the payload is JSON or numeric, switch mqttCheckType to 'json-query' or add monitor.conditions instead of relying on raw substring matching.
  3. Make mqttSuccessMessage more specific (a token that only appears in the success state) to avoid matching unrelated retained messages.
  4. If the topic sometimes carries retained/empty messages, publish a fresh retained message with the expected payload or clear retained state.

Example fix

// before: monitor.mqttSuccessMessage = "ok"  (payload is JSON {"state":"ON"})
// after:
monitor.mqttSuccessMessage = '"state":"ON"';
// or switch to json-query with jsonPath='state' and expectedValue='ON'
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate config before relying on the monitor:
function isValidKeywordMonitor(m) {
  return typeof m.mqttSuccessMessage === 'string' && m.mqttSuccessMessage.length > 0
      && typeof m.mqttTopic === 'string' && m.mqttTopic.length > 0;
}

Type guard

function isKeywordCheck(m) { return (m.mqttCheckType == null || m.mqttCheckType === '') || m.mqttCheckType === 'keyword'; }

Try / catch

try {
  mqttMonitor.checkKeyword(monitor, heartbeat, topic, msg);
} catch (e) {
  if (/Message Mismatch/.test(e.message)) { heartbeat.status = DOWN; heartbeat.msg = e.message; }
  else throw e;
}

Prevention

When it happens

Trigger: mqttCheckType is 'keyword' (the default when monitor.mqttCheckType is null/empty) and no monitor.conditions are defined, AND (receivedMessage == null OR !receivedMessage.includes(monitor.mqttSuccessMessage)). The message is delivered via the 'message' event in mqttAsync and converted with message.toString('utf8').

Common situations: mqttSuccessMessage left blank or copy-pasted with trailing whitespace; publisher changed its payload format; an empty retained message is delivered on the topic; binary/non-UTF8 payloads get garbled by toString('utf8') and no longer contain the keyword; case mismatch (e.g. 'ON' vs 'on').

Related errors


AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12). Data as JSON: /api/errors/bbae2de3e48bb492. Report an issue: GitHub.