{"record":{"id":"bbae2de3e48bb492","repo":"louislam/uptime-kuma","slug":"message-mismatch-topic-monitor-mqtttopic-me","errorCode":null,"errorMessage":"Message Mismatch - Topic: ${monitor.mqttTopic}; Message: ${receivedMessage}","messagePattern":"Message Mismatch - Topic: (.+?); Message: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/monitor-types/mqtt.js","lineNumber":66,"sourceCode":"            throw new Error(\"Unknown MQTT Check Type\");\n        }\n    }\n\n    /**\n     * Check using keyword matching\n     * @param {object} monitor Monitor object\n     * @param {object} heartbeat Heartbeat object\n     * @param {string} messageTopic Received MQTT topic\n     * @param {string} receivedMessage Received MQTT message\n     * @returns {void}\n     * @throws {Error} If keyword is not found in message\n     */\n    checkKeyword(monitor, heartbeat, messageTopic, receivedMessage) {\n        if (receivedMessage != null && receivedMessage.includes(monitor.mqttSuccessMessage)) {\n            heartbeat.msg = `Topic: ${messageTopic}; Message: ${receivedMessage}`;\n            heartbeat.status = UP;\n        } else {\n            throw new Error(`Message Mismatch - Topic: ${monitor.mqttTopic}; Message: ${receivedMessage}`);\n        }\n    }\n\n    /**\n     * Check using JSONata query\n     * @param {object} monitor Monitor object\n     * @param {object} heartbeat Heartbeat object\n     * @param {string} receivedMessage Received MQTT message\n     * @returns {Promise<void>}\n     */\n    async checkJsonQuery(monitor, heartbeat, receivedMessage) {\n        const parsedMessage = JSON.parse(receivedMessage);\n        const expression = jsonata(monitor.jsonPath);\n        const result = await expression.evaluate(parsedMessage);\n\n        if (result?.toString() === monitor.expectedValue) {\n            heartbeat.msg = \"Message received, expected value is found\";\n            heartbeat.status = UP;","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/monitor-types/mqtt.js#L48-L84","documentation":"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.","triggerScenarios":"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').","commonSituations":"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').","solutions":["Confirm the exact bytes the publisher sends (e.g. mosquitto_sub -t '<topic>') and paste a unique substring of that payload into mqttSuccessMessage.","If the payload is JSON or numeric, switch mqttCheckType to 'json-query' or add monitor.conditions instead of relying on raw substring matching.","Make mqttSuccessMessage more specific (a token that only appears in the success state) to avoid matching unrelated retained messages.","If the topic sometimes carries retained/empty messages, publish a fresh retained message with the expected payload or clear retained state."],"exampleFix":"// before: monitor.mqttSuccessMessage = \"ok\"  (payload is JSON {\"state\":\"ON\"})\n// after:\nmonitor.mqttSuccessMessage = '\"state\":\"ON\"';\n// or switch to json-query with jsonPath='state' and expectedValue='ON'","handlingStrategy":"try-catch","validationCode":"// Validate config before relying on the monitor:\nfunction isValidKeywordMonitor(m) {\n  return typeof m.mqttSuccessMessage === 'string' && m.mqttSuccessMessage.length > 0\n      && typeof m.mqttTopic === 'string' && m.mqttTopic.length > 0;\n}","typeGuard":"function isKeywordCheck(m) { return (m.mqttCheckType == null || m.mqttCheckType === '') || m.mqttCheckType === 'keyword'; }","tryCatchPattern":"try {\n  mqttMonitor.checkKeyword(monitor, heartbeat, topic, msg);\n} catch (e) {\n  if (/Message Mismatch/.test(e.message)) { heartbeat.status = DOWN; heartbeat.msg = e.message; }\n  else throw e;\n}","preventionTips":["Subscribe with mosquitto_sub once and copy a unique substring of the real payload into mqttSuccessMessage.","Avoid blank mqttSuccessMessage — an empty string .includes() always matches and hides real failures.","Prefer conditions or json-query for structured payloads."],"tags":["mqtt","monitor","content-mismatch","uptime-kuma"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}