Throwing errors - help please

(Me again)

I have worked out how to throw an error.

The error message works and all is good.......

but.....

Subflows. (My favorite things it would seem)

I have tested if the incoming message structure is correct and if not, throw an error.

Good/Bad.

Good, I get the error message.
Bad: I would prefer it says it is the SUBFLOW - and not the node in it - with the error.

How would I get that to work?

You wan't to stop messages from being passed to the next node?

In this case I just throw new Error:

        if (!ignoreErrors){
            if(folders.indexOf(plc.Plc) === -1)
                throw new Error(`${plc.Plc} existing in relationship map but no folder in work directory`)
        }
        else if (folders.indexOf(plc.Plc) === -1){
            node.error(`${plc.Plc} existing in relationship map but no folder in work directory`)
            compareResult = false;
        }

I think we are talking about different things.

This is my subflow.

[{"id":"a29b660bf678ae94","type":"subflow","name":"offline","info":"2024 02 10\n==========\n\nInput:\n------\n\n`topic` is the IP address\n\n`payload` is anything - but usually\nthe `nmap` responce time.\n\n`delay` needs to be set to a value\nto control the timeout period\n\nWill now throw an error if not set.\n\nOutput:\n------\n\n`ip_address` is the last 2 octets of\nof the IP address.\nUsed if the indicator needs this.\n\nSTATUS:\n------\n\nShows device status.\n\n\n\n2022 12 27\nHopfully better working.\n\n2022 12 26\n`msg.ip_address` is the last 2 octets\nof the IP address.\n","category":"","in":[{"x":100,"y":140,"wires":[{"id":"10d89115b954c0e5"}]}],"out":[{"x":970,"y":140,"wires":[{"id":"f7a5739094e4627b","port":0}]}],"env":[],"meta":{},"color":"#DD4040","icon":"node-red/status.svg","status":{"x":970,"y":290,"wires":[{"id":"4ad44ebed6115a2a","port":0}]}},{"id":"8dcd00765893e1a1","type":"trigger","z":"a29b660bf678ae94","name":"OffLineA","op1":"","op2":"Off-line","op1type":"nul","op2type":"str","duration":"5","extend":true,"overrideDelay":true,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":650,"y":180,"wires":[["6f013d1da2275af3","f7a5739094e4627b"]]},{"id":"27779426545d8713","type":"trigger","z":"a29b660bf678ae94","name":"OffLineB","op1":"","op2":"Off-line","op1type":"nul","op2type":"str","duration":"5","extend":true,"overrideDelay":true,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":650,"y":220,"wires":[["7fb1ac33c4a9d845"]]},{"id":"6f013d1da2275af3","type":"change","z":"a29b660bf678ae94","name":"","rules":[{"t":"set","p":"delay","pt":"msg","to":"msg.delay / 2","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":535,"y":220,"wires":[["27779426545d8713"]],"l":false},{"id":"06decc75cc1be73b","type":"switch","z":"a29b660bf678ae94","name":"Not `BOOT SIGNAL`","property":"payload","propertyType":"msg","rules":[{"t":"neq","v":"BOOT SIGNAL","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":535,"y":140,"wires":[["f7a5739094e4627b"]],"l":false},{"id":"7fb1ac33c4a9d845","type":"trigger","z":"a29b660bf678ae94","name":"OffLineC","op1":"","op2":"","op1type":"pay","op2type":"pay","duration":"5","extend":true,"overrideDelay":true,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":810,"y":220,"wires":[["f7a5739094e4627b"]]},{"id":"f7a5739094e4627b","type":"function","z":"a29b660bf678ae94","name":"ip_address","func":"var y = msg.topic.substring(7);\nmsg.ip_address = y;\nnode.status({ text: msg.payload });\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":820,"y":140,"wires":[[]]},{"id":"58c43f990cfcc4ed","type":"status","z":"a29b660bf678ae94","name":"IP_address","scope":["f7a5739094e4627b"],"x":400,"y":290,"wires":[["d05b7d56d254176c"]]},{"id":"d05b7d56d254176c","type":"change","z":"a29b660bf678ae94","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"status.text","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":600,"y":290,"wires":[["4ad44ebed6115a2a"]]},{"id":"4ad44ebed6115a2a","type":"function","z":"a29b660bf678ae94","name":"function 7","func":"if (msg.payload == \"Off-line\") {\n    msg.payload = ({ fill: \"red\", text: \"Offline\" });\n}\nif (msg.payload == \"On-line\") {\n    msg.payload = ({ fill: \"green\", text: \"Online\" });\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":810,"y":290,"wires":[[]]},{"id":"10d89115b954c0e5","type":"function","z":"a29b660bf678ae94","name":"Check msg.delay exists","func":"if (msg.delay == undefined)\n{\n    throw \"msg.delay must be set\"\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":140,"wires":[["06decc75cc1be73b","8dcd00765893e1a1"]]},{"id":"9e8a6ffda39f4476","type":"subflow:a29b660bf678ae94","z":"c636aa5a.cc34","name":"","x":465,"y":830,"wires":[["61c14247.5f3384"]],"l":false}]

Being a subflow, it has many/multiple appearances in my flows.

It needs a msg.delay to be in the incoming message.

So I put a code in there that if the msg.delay == undefined it throws an error.

Of course that is good, but can you see the problem?

I don't get told from WHICH ONE the error is coming.

I'm stupid, I can't see/understand what your code is supposed to do.

Why not define env variables for each instance of subflow?

[{"id":"a29b660bf678ae94","type":"subflow","name":"offline","info":"2024 02 10\n==========\n\nInput:\n------\n\n`topic` is the IP address\n\n`payload` is anything - but usually\nthe `nmap` responce time.\n\n`delay` needs to be set to a value\nto control the timeout period\n\nWill now throw an error if not set.\n\nOutput:\n------\n\n`ip_address` is the last 2 octets of\nof the IP address.\nUsed if the indicator needs this.\n\nSTATUS:\n------\n\nShows device status.\n\n\n\n2022 12 27\nHopfully better working.\n\n2022 12 26\n`msg.ip_address` is the last 2 octets\nof the IP address.\n","category":"","in":[{"x":100,"y":140,"wires":[{"id":"10d89115b954c0e5"}]}],"out":[{"x":970,"y":140,"wires":[{"id":"f7a5739094e4627b","port":0}]}],"env":[{"name":"id","type":"str","value":"device"}],"meta":{},"color":"#DD4040","icon":"node-red/status.svg","status":{"x":970,"y":290,"wires":[{"id":"4ad44ebed6115a2a","port":0}]}},{"id":"8dcd00765893e1a1","type":"trigger","z":"a29b660bf678ae94","name":"OffLineA","op1":"","op2":"Off-line","op1type":"nul","op2type":"str","duration":"5","extend":true,"overrideDelay":true,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":650,"y":180,"wires":[["6f013d1da2275af3","f7a5739094e4627b"]]},{"id":"27779426545d8713","type":"trigger","z":"a29b660bf678ae94","name":"OffLineB","op1":"","op2":"Off-line","op1type":"nul","op2type":"str","duration":"5","extend":true,"overrideDelay":true,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":650,"y":220,"wires":[["7fb1ac33c4a9d845"]]},{"id":"6f013d1da2275af3","type":"change","z":"a29b660bf678ae94","name":"","rules":[{"t":"set","p":"delay","pt":"msg","to":"msg.delay / 2","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":535,"y":220,"wires":[["27779426545d8713"]],"l":false},{"id":"06decc75cc1be73b","type":"switch","z":"a29b660bf678ae94","name":"Not `BOOT SIGNAL`","property":"payload","propertyType":"msg","rules":[{"t":"neq","v":"BOOT SIGNAL","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":535,"y":140,"wires":[["f7a5739094e4627b"]],"l":false},{"id":"7fb1ac33c4a9d845","type":"trigger","z":"a29b660bf678ae94","name":"OffLineC","op1":"","op2":"","op1type":"pay","op2type":"pay","duration":"5","extend":true,"overrideDelay":true,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":810,"y":220,"wires":[["f7a5739094e4627b"]]},{"id":"f7a5739094e4627b","type":"function","z":"a29b660bf678ae94","name":"ip_address","func":"var y = msg.topic.substring(7);\nmsg.ip_address = y;\nnode.status({ text: msg.payload });\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":820,"y":140,"wires":[[]]},{"id":"58c43f990cfcc4ed","type":"status","z":"a29b660bf678ae94","name":"IP_address","scope":["f7a5739094e4627b"],"x":400,"y":290,"wires":[["d05b7d56d254176c"]]},{"id":"d05b7d56d254176c","type":"change","z":"a29b660bf678ae94","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"status.text","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":600,"y":290,"wires":[["4ad44ebed6115a2a"]]},{"id":"4ad44ebed6115a2a","type":"function","z":"a29b660bf678ae94","name":"function 7","func":"if (msg.payload == \"Off-line\") {\n    msg.payload = ({ fill: \"red\", text: \"Offline\" });\n}\nif (msg.payload == \"On-line\") {\n    msg.payload = ({ fill: \"green\", text: \"Online\" });\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":810,"y":290,"wires":[[]]},{"id":"10d89115b954c0e5","type":"function","z":"a29b660bf678ae94","name":"Check msg.delay exists","func":"const id = env.get(\"id\")\n\nif (msg.delay == undefined)\n{\n    throw `msg.delay for device: ${id} must be set`\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":140,"wires":[["06decc75cc1be73b","8dcd00765893e1a1"]]},{"id":"9e8a6ffda39f4476","type":"subflow:a29b660bf678ae94","z":"17544288b1b6c2c1","name":"","env":[{"name":"id","value":"1","type":"str"},{"name":"IP","value":"device1","type":"str"}],"x":1695,"y":120,"wires":[[]],"l":false}]

also I see you use msg.ip_address, can't you just incorporate that in your error text to know which device you are trying to monitor?

msg.ip_address is used/needed by the downstream nodes if it is working.
This thread is/was about throwing an error if the msg.delay isn't set in the incoming message.

But thanks for that code in the function node.

I didn't think of that trick.

Seems to work.

(You could have saved a lot of fuss by just posting that function node, or even just the code in it. The code isn't that big.)

Um, it doesn't work. I think.

Why?

Well, this is an example of a worst case scenario.....
Look at piccie.

So, there are multiple instances of the offline subflow.

One of them doesn't get a msg.delay. The catch node and error are on the right.

Node name...... source.
Yeah, that is the function node in the subflow, but it can't be found and doesn't point to THE node which just got the incorrect message.

I need the source node id should be that instance of the subflow.

Digging further I found this:

https://nodered.org/docs/user-guide/environment-variables

NR_SUBFLOW_ID

How do I access that?

const id = env.get(NR_SUBFLOW_ID) doesn't work.

Ah, NR 3.1.x......

Not 3.0.2

Please confirm.

Is there a way in 3.0.2?

When you type in env.get( you are shown info popup in the Monaco editor that states it should be a string

Also, you'll probably get a red squiggle underneath what you write that will also tell you what you wrote is wrong

In short: env.get("NR_SUBFLOW_ID")

Thanks....

But wanting to check:

This will work in/on 3.0.2?

Pretty easy to check.

From the doc you linked.

NR_SUBFLOW_ID - the ID of the containing subflow instance node (since Node-RED 3.1)

So no. You'll need v3.1.x

Yes it is.

Did and it kinda works.

BUT - alas....

I am still not given the SUBFLOW's ID in the error.

When I search for the source node's ID (from the error message) it says there is no such node.

So why is the name accepted?

It probably is because it is inside " " - which kinda throws me for a 6.

And that will return ... something that will stuff up the rest.

yes?

Have you tried putting NR_NODE_PATH in your message?

E.g.

const err = `Bad message detected: ${env.get("NR_NODE_PATH")}`
node.error(err, msg)
1 Like

SORRY!

Ok, if I look a bit more/harder at the error message:

{"_msgid":"70c9f59eaf700442",
"payload":1707642425224,
"topic":"",
"error":{"message":"msg.delay for device: b35c18234f82cf9e must be set","source":{"id":"b35c18234f82cf9e-10d89115b954c0e5","type":"function","name":"Check msg.delay exists","count":1}}}

The line: message":"msg.delay for device: b35c18234f82cf9e must be set" the number there points to the subflow.

So it does work.

It is just I need to make sure the error message has the needed information needed.

That structure has red text when I paste it in the function node.

(Sorry, is it just my stupidity that is tripping me up?)
That's new to NR 3.1.... Yeah?

No. It's available pre 3.1

The coloured brackets are a visual aid to help you match them up to their partner.

Yeah, my stupidity.

They could have picked a better colour than RED.
People like me see red and think ERROR.
(Dunno why)
:wink:

Ok, cutting down to THAT node in the subflow.

This:

if (msg.delay == undefined) {
    //
    const idb = `${env.get("NR_NODE_PATH")}`;
    let ids = idb.split("/");
    const errr = `msg.delay not set in message going into errr`;
    node.error(errr,msg);
    return;
}
return msg;

Why am I seeing TypeError: msg.payload.split is not a function?

msg.payload.split is not shown in that code so it's not coming from there

1 Like

Sorry, that was a mistake my end:

This should be the code....

(I'm sure you can see what I am trying to do.)

const id  = env.get("NR_NODE_PATH")

if (msg.delay == undefined) {
    //


    node.warn("Error detected " + id)
    let y = id;
    node.warn(y);

    //const idb = `${env.get("NR_NODE_PATH")}`;
    //let ids = idb.split("/");
    let ids = id.split("/");
    const errr = `msg.delay not set in message going into errr`;
    node.error(errr,msg);
    return;

    //throw `msg.delay for device: ${id} must be set`
}
return msg;

This has been edited, as there was a lot of stuff in there that shouldn't have been there.

(Still doesn't work though.)

That way I get the subflow's ID and not it and the actual function node's ID stuck on the end.

Then when I get the error message the source id (or what ever) is THE ID.

Sorry, yeah, I'm being anal about this.
But it just seems it shouldn't be impossible (even on 3.0.x) to get it if in the code you posted I am getting to see it, but with other stuff around it.

That will work on 3.0.x too - yes?

The above is based on this bit of code:

(3 nodes)

[{"id":"3027702043cf70d0","type":"function","z":"0918ee609bf69fc7","name":"function 39","func":"let y = msg.payload.split(\"/\");\nnode.warn(y);\n\nmsg.payload = y[1];\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":3650,"y":2930,"wires":[["085b74ddd9309b27"]]},{"id":"2a7c650b3e5cc9a0","type":"inject","z":"0918ee609bf69fc7","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0918ee609bf69fc7/b35c18234f82cf9e/10d89115b954c0e5","payloadType":"str","x":3510,"y":2930,"wires":[["3027702043cf70d0"]]},{"id":"085b74ddd9309b27","type":"debug","z":"0918ee609bf69fc7","name":"debug 339","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":3860,"y":2930,"wires":[]}]

That takes what your code gives me and gets/extracts the subflow's ID.
Then that is used.

So taking that code..... Why doesn't it work in the subflow?