Zie619/n8n-workflows · error · Error
Invalid JSON in MQTT message
Error message
Invalid JSON in MQTT message
What it means
Thrown by the 'Payload data preparation node' Code node in the MQTT monitor workflow. It runs JSON.parse($json.message) and throws this exact message when the parse throws — i.e. $json.message exists but is not valid JSON text. Every other failure mode (missing humidity/temp) throws a different message, so this error is precisely 'the MQTT message body is not parseable JSON'.
Source
Thrown at workflows/Http/1110_HTTP_Mqtt_Monitor_Webhook.json:130
"value": "Token <API Token value generated in InfluxDB>"
}
]
}
},
"notesInFlow": true,
"typeVersion": 4.2,
"notes": "This httpRequest node performs automated tasks as part of the workflow."
},
{
"id": "6abe1212-b128-492f-b485-401a4315fcbc",
"name": "Payload data preparation node",
"type": "n8n-nodes-base.code",
"position": [
-180,
-220
],
"parameters": {
"jsCode": "// Try to parse the incoming message as JSON\nlet data;\ntry {\n data = JSON.parse($json.message); // $json.message is expected to be a JSON string\n} catch (e) {\n // If parsing fails, throw an error\n throw new Error(\"Invalid JSON in MQTT message\");\n}\n\n// Get the topic from the input, or use a default value\nconst topic = $json.topic || \"unknown-topic\";\n\n// Make sure humidity and temp are numbers\nif (typeof data.humidity !== \"number\" || typeof data.temp !== \"number\") {\n throw new Error(\"Missing or invalid humidity/temp in MQTT message\");\n}\n\n// Create a formatted string like: \"topic_name humidity=45,temp=22\"\nconst line = `${topic} humidity=${data.humidity},temp=${data.temp}`;\n\n// Return the result in the expected format\nreturn [\n {\n json: {\n payload: line\n }\n }\n];"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": null,
"timezone": "UTC",
"executionTimeout": 3600,
"maxExecutions": 1000,
"retryOnFail": true,
"retryCount": 3,
"retryDelay": 1000View on GitHub (pinned to 94007c1445)
Solutions
- Run the trigger once and inspect the incoming item to find where the payload actually lives ($json.message vs $json.payload vs nested).
- Pre-validate before parsing: handle undefined message and base64 payloads explicitly (see exampleFix).
- If the device cannot send JSON, parse its native format (split on comma) instead of JSON.parse.
- Fix the device/broker to publish JSON, or add a normalizer step before this node.
Example fix
// before
let data;
try {
data = JSON.parse($json.message);
} catch (e) {
throw new Error("Invalid JSON in MQTT message");
}
// after
const raw = $json.message ?? $json.payload ?? '';
if (typeof raw !== 'string' || !raw.trim()) {
throw new Error(`No MQTT payload received (topic=${$json.topic ?? 'unknown'})`);
}
let data;
try {
data = JSON.parse(raw);
} catch (e) {
// some brokers base64-encode binary payloads
try { data = JSON.parse(Buffer.from(raw, 'base64').toString('utf8')); }
catch (e2) { throw new Error(`Invalid JSON in MQTT message: ${raw.slice(0, 80)}`); }
} Defensive patterns
Strategy: try-catch
Validate before calling
const raw = $json.message ?? $json.payload ?? '';
const looksJson = typeof raw === 'string' && raw.trim().startsWith('{');
if (!looksJson && /^[A-Za-z0-9+/=]+$/.test(raw)) {
// likely base64: Buffer.from(raw, 'base64').toString('utf8')
} Type guard
function isJsonMqttMessage(msg) {
return typeof msg === 'string' && msg.trim().startsWith('{') && msg.trim().endsWith('}');
} Try / catch
let data;
try {
data = JSON.parse(raw);
} catch (e) {
throw new Error(`Invalid JSON in MQTT message (topic=${$json.topic}, first 80 chars: ${String(raw).slice(0, 80)})`);
} Prevention
- Fix device firmware to publish JSON, or normalize the native format with split() instead of JSON.parse.
- Check for base64-encoded payloads from broker bridges before parsing.
- Include topic and a payload excerpt in the error so offending devices are identifiable.
When it happens
Trigger: An MQTT webhook forwards a sensor publish whose payload is plain text (e.g. '22.5,45') or base64/binary rather than a JSON string like '{"temp":22,"humidity":45}'. It also throws when $json.message is undefined because JSON.parse(undefined) throws — so a payload delivered under a different key (payload, data, body) hits the same catch.
Common situations: ESP8266/ESP32 firmware publishing comma-separated values instead of JSON; MQTT broker bridge base64-encoding binary payloads; the webhook trigger nesting the payload under $json.payload.data while the code reads $json.message; devices occasionally publishing empty retained messages.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Seats data is missing or invalid.
- Invalid quantity: ${input["Quantity Received"]}
- Invalid price: ${input["Unit Price"]}
- Invalid quantity Requested: ${quantityRequested}. Must be gr
- Product ID is missing
AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15).
Data as JSON: /api/errors/fbf2cb0c23403866.
Report an issue: GitHub.