Bug? using `change` node (jsonata) to add non-existing flow/global variables generates no error

NR v3.0.2

If you use use jsonata in a change node and try to add flow/global variables together and one of the flow/global variables does not exist, no error and no result is returned.

Example flow:

[{"id":"1b34f2e69b481f3d","type":"inject","z":"51b4376bd7d81c4b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"55","payloadType":"num","x":130,"y":120,"wires":[["7c08c8263ebca986"]]},{"id":"7c08c8263ebca986","type":"change","z":"51b4376bd7d81c4b","name":"","rules":[{"t":"set","p":"var1","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":150,"y":180,"wires":[["4204bdfb2b189e0f"]]},{"id":"9ac824b955284c63","type":"debug","z":"51b4376bd7d81c4b","name":"debug 3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":140,"y":300,"wires":[]},{"id":"92c935c39b9f84fb","type":"catch","z":"51b4376bd7d81c4b","name":"","scope":null,"uncaught":false,"x":340,"y":140,"wires":[["7cc339226879bd18"]]},{"id":"7cc339226879bd18","type":"debug","z":"51b4376bd7d81c4b","name":"debug 4","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":500,"y":140,"wires":[]},{"id":"4204bdfb2b189e0f","type":"change","z":"51b4376bd7d81c4b","name":"add three flow variables together","rules":[{"t":"set","p":"payload","pt":"msg","to":"$flowContext('var1')+$flowContext('var2')+$flowContext('var3')","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":220,"y":240,"wires":[["9ac824b955284c63"]]}]

try

$sum([
    $flowContext('var1'),
    $flowContext('var2'),
    $flowContext('var3')
])

If one is not defined it can not be added using +, but can be sum()'ed.
There are other cases where the behaviour you see occurs, it can be helpful at time.

the question is should it throw an error instead of returning nothing?

if no property is set as there is an undefined, you then can detect it in flow to continue or not, as said i find this help full at times, as i can stop the flow without error handling from another flow. So my vote is I like it this way.

I don't think this is a bug, but I'm less comfortable with it than @E1cid. There may also be more going on. In this version of @zenofmud's flow, the function node does what I would expect in JavaScript: the undefined flow variables are returned as undefined, the sum is NaN, and there is no error. The change node seems to ignore any property that is undefined, and JSONata behaves differently than JS. Everything may be working as intended, but the inconsistency is a bit off-putting.

[{"id":"1b34f2e69b481f3d","type":"inject","z":"edd7b753d67c3de6","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"55","payloadType":"num","x":190,"y":60,"wires":[["7c08c8263ebca986"]]},{"id":"7c08c8263ebca986","type":"change","z":"edd7b753d67c3de6","name":"","rules":[{"t":"set","p":"var1","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":210,"y":140,"wires":[["16f98cf758e70bcc","4204bdfb2b189e0f"]]},{"id":"92c935c39b9f84fb","type":"catch","z":"edd7b753d67c3de6","name":"","scope":null,"uncaught":false,"x":380,"y":60,"wires":[["7cc339226879bd18"]]},{"id":"7cc339226879bd18","type":"debug","z":"edd7b753d67c3de6","name":"debug 4","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":540,"y":60,"wires":[]},{"id":"4204bdfb2b189e0f","type":"change","z":"edd7b753d67c3de6","name":"change to add 3 flow variables","rules":[{"t":"set","p":"payload","pt":"msg","to":"$flowContext('var1')+$flowContext('var2')+$flowContext('var3')","tot":"jsonata"},{"t":"set","p":"var1","pt":"msg","to":"var1","tot":"flow"},{"t":"set","p":"var2","pt":"msg","to":"var2","tot":"flow"},{"t":"set","p":"var3","pt":"msg","to":"var3","tot":"flow"},{"t":"set","p":"test0","pt":"msg","to":"var1 + var2 + var3","tot":"jsonata"},{"t":"set","p":"test1","pt":"msg","to":"$sum([$flowContext('var1'),$flowContext('var2'),$flowContext('var3') ])","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":160,"wires":[["f672c0dbd3d4de96"]]},{"id":"16f98cf758e70bcc","type":"function","z":"edd7b753d67c3de6","name":"function to add 3 flow variables","func":"msg.var1 = flow.get('var1')\nmsg.var2 = flow.get('var2')\nmsg.var3 = flow.get('var3')\nmsg.payload = flow.get('var1') + flow.get('var2') + flow.get('var3')\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":120,"wires":[["f672c0dbd3d4de96"]]},{"id":"f672c0dbd3d4de96","type":"debug","z":"edd7b753d67c3de6","name":"debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":670,"y":140,"wires":[]}]
1 Like

I agree with everything working as intended. As for the inconsistency, this is not ours to question - it is what JSONata does as far as I can see.

For example,

If you add 55 and 2 undefined, you get nothing...
image

If you sum 55 and 2 undefined, you get 55...
image

And if you put the values in an array, you can see why $sum(var1,var2,var3) returns [55] ...
image


The results are same in node-red...

So to summarise, node-red is doing what JSONata intends as far as I can see.

@Steve-Mcl the thing is that with the example I provide, there is no msg.payload in the output msg from the change node.

I guess this means that when using JSONata you better examine the results before trying to use it :slightly_frowning_face:

Yeah, I did see that Paul - to be clear, the JSONata outputs nothing (as in "not a null" / "not an undefined" - it literally doesn't output anything). This is how node-red currently represents that JSONata behaviour.

I'm not saying it should or shouldn't output a payload: null or payload: undefined or payload: NaN or even throw an error, just that doesnt and that is its current behaviour - and some users flows will now likely depend on that behaviour. Something that, if were to be changed, would only happen in a major Version release (next one is v4.0.0). If users feel strongly about this, then please raise an issue so that it is tracked. Nick may reject it but sitting here alone it will be missed.

I mentioned one thing that is strictly a NR (not JSONata) issue. The function and change nodes seem to treat undefined context variables differently.

[{"id":"f3402886d726ed8e","type":"inject","z":"edd7b753d67c3de6","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"55","payloadType":"num","x":190,"y":240,"wires":[["9a2f9e298ebfdb10"]]},{"id":"9a2f9e298ebfdb10","type":"change","z":"edd7b753d67c3de6","name":"","rules":[{"t":"set","p":"var1","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":210,"y":300,"wires":[["a3cbfa87b1e424fe","85ebed23269f0e77"]]},{"id":"a3cbfa87b1e424fe","type":"function","z":"edd7b753d67c3de6","name":"function to get 3 flow variables","func":"msg.var1 = flow.get('var1')\nmsg.var2 = flow.get('var2')\nmsg.var3 = flow.get('var3')\n// msg.payload = flow.get('var1') + flow.get('var2') + flow.get('var3')\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":280,"wires":[["9a2a484c67f51362"]]},{"id":"85ebed23269f0e77","type":"change","z":"edd7b753d67c3de6","name":"change to get 3 flow variables","rules":[{"t":"set","p":"payload","pt":"msg","to":"$flowContext('var1')+$flowContext('var2')+$flowContext('var3')","tot":"jsonata"},{"t":"set","p":"var1","pt":"msg","to":"var1","tot":"flow"},{"t":"set","p":"var2","pt":"msg","to":"var2","tot":"flow"},{"t":"set","p":"var3","pt":"msg","to":"var3","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":320,"wires":[["9a2a484c67f51362"]]},{"id":"9a2a484c67f51362","type":"debug","z":"edd7b753d67c3de6","name":"debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":670,"y":300,"wires":[]}]

I disagree. JSONata is NOT returning a value and "no value" is represented by "no property" in JS. "No property" is different to a property: null, property: undefined, etc etc

Just because the function node does what it does (which btw is because you assigned an undefined to a property of an object [aka the msg]) does not mean that is how the JSONata in a change MUST work when faced with an undefined value.

Look at the array example...

... its like the values dont exist (as in not a null, not an undefined).

Try for yourself in the playground


Even after all that :point_up_2: it changes nothing to what I already said...

I understand and agree with everything you said, but I am now more confused. My example has nothing to do with JSONata. I don't understand why

msg.var2 = flow.get('var2')

in a function node should return undefined while

in a change node returns "no property."

Sorry Mike, I missed that detail.

The behaviour (in a function node) is absolutely correct and as you demonstrate works as designed.

This behaviour is debateable for sure but I am faily certain I know why this one does this (this time tho, I am not certain it is right or hasn't changed). Does anyone know if this behaviour has changed between V1 ~ v2 ~ v3?

I'll test it on v3.0.2, v2.2.2 and v1.3.5

So I ran the flow on each of the versions - It looks like the same thing occurs in all three versions - I renamed the inject node with the version number for each run.
NR v1.3.5

NR v2.2.2

NR v3.0.2

1 Like