This is the first time that NR actually crashes on a specific flow. I guess that will be tricky to debug..
I got a data stream for my BMW car via an external aggregator
(Project BMW CarData → MQTT Bridge) . There had been an equivalent NR node but it's no longer functional.
When the car sends the data it will be a stream of about 10-20 MQTT messages, sometimes even double messages with same topics. I am catching these messages with a function node and "distribute" and sort the parameters in different flow variables for further processing:
[
{
"id": "c727cd363836fe5c",
"type": "tab",
"label": "Flow 1",
"disabled": false,
"info": "",
"env": []
},
{
"id": "5b67aa09c7333225",
"type": "mqtt in",
"z": "c727cd363836fe5c",
"name": "BWM CarDataStream",
"topic": "bmw/WTT5A110607J29109/#",
"qos": "0",
"datatype": "json",
"broker": "43078758.727338",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 280,
"y": 300,
"wires": [
[
"9a15f9a3fe6a7205"
]
]
},
{
"id": "9a15f9a3fe6a7205",
"type": "function",
"z": "c727cd363836fe5c",
"name": "set flow variables (single topic)",
"func": "// proper parameter name now in payload.data\n\nfunction mergeFlatKeysIntoNestedDict(newDict, inputObj, { omitFirst = true, maxDepth = 50 } = {}) {\n for (const fullKey of Object.keys(inputObj)) {\n const parts = fullKey.split(\".\").filter(Boolean);\n let path = omitFirst ? parts.slice(2) : parts;\n\n if (path.length === 0) continue;\n\n // target is a pointer for newDict (avoid shadowing Node-RED's `node`)\n let target = newDict;\n\n for (let i = 0; i < path.length; i++) {\n const seg = path[i];\n const isLeaf = i === path.length - 1;\n\n if (isLeaf) { // final Leaf of the tree, now assign value\n// node.warn(newDict);\n target[seg] = inputObj[fullKey]; // add/overwrite only this leaf\n } else {\n // ensure branch exists; if something non-object is there, replace it\n if (typeof target[seg] !== \"object\" || target[seg] === null || Array.isArray(target[seg])) {\n target[seg] = {};\n }\n // move pointer down to new child\n target = target[seg];\n }\n }\n }\n return newDict;\n}\n\nconst para = msg.payload.data\n\n// get name of flow variable \nif (!para || typeof para !== \"object\") {\n node.warn(\"Expected msg.payload.data to be an object\");\n return { payload: {} };\n}\n\nconst key = Object.keys(para)[0];\nif (!key) {\n node.warn(\"msg.payload.data had no keys\");\n return { payload: {} };\n}\n\nconst nameParts = key.split('.');\nconst name = nameParts[1] ?? nameParts[0];\nnode.warn(`flow variable name: ${name}`)\n\n// read old values if present\nvar para_field = flow.get(name)\nif (para_field == undefined) {\n para_field = {}; //define first\n}\nmergeFlatKeysIntoNestedDict(para_field, para);\nflow.set(name, para_field)\nreturn { \"payload\": para_field }\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 590,
"y": 300,
"wires": [
[
"c4801b6a0f3040ef",
"e1d306ae278ad009"
]
],
"info": "still not complete\n.env file should better include the option SPLIT_TOPICS=1"
},
{
"id": "c4801b6a0f3040ef",
"type": "change",
"z": "c727cd363836fe5c",
"name": "Flow.drivetrain",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "drivetrain",
"tot": "flow",
"dc": true
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 900,
"y": 300,
"wires": [
[]
]
},
{
"id": "e1d306ae278ad009",
"type": "change",
"z": "c727cd363836fe5c",
"name": "Flow.cabin",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "cabin",
"tot": "flow",
"dc": true
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 890,
"y": 380,
"wires": [
[]
]
},
{
"id": "43078758.727338",
"type": "mqtt-broker",
"name": "Smarthome",
"broker": "192.168.178.40",
"port": "1883",
"clientid": "SMARTHOME",
"autoConnect": true,
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"autoUnsubscribe": true,
"birthTopic": "",
"birthQos": "0",
"birthRetain": "false",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closeRetain": "false",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willRetain": "false",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
}
]
Every time a data streams arrives NR dashboard gets "offline", and according to the node.warn() messages visible in the log file the function node processes some messages even minutes(!) after receiving.
I observe 2 specific error messages in the log:
3 Apr 16:33:42 - [info] [mqtt-broker:Smarthome] Disconnected from broker: SMARTHOME@mqtt://192.168.178.40:1883
3 Apr 16:33:42 - [info] [zigbee2mqtt-server:Z2M Broker] MQTT Reconnect
3 Apr 16:36:14 - [info] [zigbee2mqtt-server:Z2M Broker] MQTT Error
(Smarthome is my local NR installation) So has my MQTT Broker an "overload" with this particular message stream? Is my ZigBee data stream interfering?
3 Apr 16:47:44 - [error] [function:set flow variables (single topic)] RangeError: Maximum call stack size exceeded
Something is wrong with my javascript function? The message to process looks like:
{"vin":"XXX6T910607JXXXX","entityId":"58b0daa7-9daa-46f1-859a-55d5169ee206","topic":"XXX6T910607JXXXX","timestamp":"2026-03-15T14:57:33.378Z","data":{"vehicle.cabin.door.status":{"timestamp":"2026-03-15T14:57:29Z","value":"UNLOCKED"}}}