"TypeError: Cannot set properties of undefined (setting 'snr')"

Hello.

I have strange and interesting behaviour of function node. Script in Function node is only to form payload. In most cases it gives correct payload, but sometimes gives error "TypeError: Cannot set properties of undefined (setting 'snr')". snr parameter is always present in same format and path. Script is following:

var device_id = msg.payload.end_device_ids.device_id;
var gateway_id=msg.payload.uplink_message.rx_metadata[0].gateway_ids.gateway_id
var snr=msg.payload.uplink_message.rx_metadata[0].snr
var rssi=msg.payload.uplink_message.rx_metadata[0].rssi
var sf=msg.payload.uplink_message.settings.data_rate.lora.spreading_factor

msg.payload.uplink_message.decoded_payload["snr"] = snr
msg.payload.uplink_message.decoded_payload["rssi"] = rssi
msg.payload.uplink_message.decoded_payload["sf"] = sf
msg.payload.uplink_message.decoded_payload["gateway_id"] = gateway_id

fields=msg.payload.uplink_message.decoded_payload
tags = {
//        "timestamp" : timestamp,
        "device_id" : device_id,
}
msg.payload=[fields, tags]
return msg;

This problem relates to snr value only.
Is there any reasonable explanation or solution to this error?

Thank You.

Hi @Roberto69

The error will be coming from the line:

msg.payload.uplink_message.decoded_payload["snr"] = snr

This is the first time you are accessing msg.payload.uplink_message.decoded_payload - so this suggests that property doesn't exist on the message the function has received.

Hi @knolleary

I guess this is beacuse snr is before other parameters - if rssi would be first, than error will relate to rssi?

How can I avoid this?

@Roberto69 that error is saying msg.payload.uplink_message.decoded_payload is NOT "something"

You have a few choices:

  1. check it is empty & throw an error or return
  2. create it if it is empty
  3. skip it if empty

1

if (!msg.payload?.uplink_message?.decoded_payload) {
    node.error("msg does not contain decoded_payload", msg)
    return
}

2

if (!msg.payload?.uplink_message?.decoded_payload) {
    msg.payload.uplink_message = msg.payload.uplink_message || {}
    msg.payload.uplink_message.decoded_payload = {}
}

3

if (msg.payload?.uplink_message?.decoded_payload) {
    msg.payload.uplink_message.decoded_payload.snr = snr
    msg.payload.uplink_message.decoded_payload.rssi = rssi
    msg.payload.uplink_message.decoded_payload.sf = sf
    msg.payload.uplink_message.decoded_payload.gateway_id = gateway_id
}

That is right.

Do you expect msg.payload.uplink_message.decoded_payload to already exist on the message or is this a new property you are wanting to create?

If its a new thing, then you can do the following to create that object with the four properties set on it:

msg.payload.uplink_message.decoded_payload = {
    snr,
    rssi,
    sf,
    gateway_id
}

Sorry, meant to post this sooner (before Nick posted). Contains a bit more info though so might still be useful.

I don't think that is true - if you comment out the msg.payload.uplink_message.decoded_payload["snr"] = snr line, I think you will find the next line errors.

My suspicion is that msg.payload.uplink_message.decoded_payload either does not exist or is not an object.

If you add a line before that section something like:

if (!msg?.payload?.uplink_message?.decoded_payload) {
   msg.payload.uplink_message.decoded_payload = {}
}

That should fix it. The ?. are a forgiving way of checking property references. The code is a way of trying to make sure that the property exists. You might also have to add more checks if it is possible that

I agree with @TotallyInformation and with @knolleary - snr is problem, but if rssi will be on the first place, problem will be with rssi.
But just to have clear starting point - all parameters as well as payload already exists. As decoded_payload not have all necessary parameters, metadata snr, rssi, sf and gateway_id are added to usefull payload and converted into tabel with function node. Maybe I didn't make optimal solution to do this, but so far it works (any propose is welcome).

This is final payload:

As proposed @Steve-Mcl , choice no. 2 sounds as the most appropriate for this case.
But it is still not clear to me why error not happening every time and I still haven't found out which condition causing error. @TotallyInformation , I'll check if msg.payload.uplink_message.decoded_payload exists in time of error

Update ... adding only device_id:

same error on node Add device_id:

Node Add device_id:

image

Again, not always. Here is output in case there is no error:

You are providing only tiny snippets of information from various things.

  • There is a "debug 41" in the flow image, but the debug message you show is from "debug 76"
  • The errors you show come from 2 different functions but only show the code from 1 function
  • The debug output you do show is an array & will never have .uplink_message.decoded_payload

The cold hard immutable fact is - when you get TypeError: Cannot set properties of undefined it means the thing you are trying to populate is undefined

i.e. msg.payload or msg.payload.uplink_message or msg.payload.uplink_messag.decode_payload is pure and simple undefined.

The reason is probably due to different payload shapes coming from the MQTT node, but as i stated earlier, you are providing only snippets of info. Does that MQTT node give types of payload?

What is debug 41 showing when there is an error?

Excuse me if I messed something.

@Colin snr parameter is present but function node shows error:

@Steve-Mcl
I'm dealing with two functions - one mentioned before (Generate Payload - v4) and this one:

device_id = msg.payload.end_device_ids.device_id;
msg.payload.uplink_message.decoded_payload["device_id"] = device_id;

msg.payload = msg.payload.uplink_message.decoded_payload
return msg;

I can't prove yet but it seems when I have debug windows open, there is no error.

Indeed, when I've opened debug window, I got an error from both function node:

Then, no single error after 60+ messages

Yes, msg.payload.uplink_message.rx_metadata[0].snr did indeed exist and had a value of 3.75.

But did msg.payload.uplink_message.decoded_payload exist, when you tried to assign the value to msg.payload.uplink_message.decoded_payload.snr ? Was it an object?

Set debug 41 to output the complete message and see what is in there when it fails.

As long as I see, device_id IS defined, but function node says it is NOT.

@Colin did you mean this?

Expand this
image

The error is not saying that device_id is not present, it is saying that msg.payload.uplink_message.decoded_payload is undefined, so it cannot set its device_id property.

Just to reinforce what everyone has already told you:
You are misunderstanding the error message.
It does not mean that device_id does not exist.
It means that msg.payload.uplink_message.decoded_payload does not exist (or it exists but is not an object)

In addition I find your code rather perplexing.
msg.payload.uplink_message.decoded_payload["gateway_id"] = gateway_id
Why are you using quotes around gateway_id inside square brackets?
You appear to be trying to assign a value to msg.payload.uplink_message.decoded_payload.gateway_id
The dot notation should work fine, provided that msg.payload.uplink_message.decoded_payload already exists.

You're right - decoded_payload is missing:

@jbudd corrected, thank you a lot:

device_id = msg.payload.end_device_ids.device_id;
msg.payload.uplink_message.decoded_payload.device_id = device_id;

msg.payload = msg.payload.uplink_message.decoded_payload
return msg;

Thank you to all for all advices - I've found out two same devices, which beside normal uplink sends uplink without decoded_payload. In this case, error happens.
Is the best way to avoid such cases to use, for example, switch node - to not decode uplink message without decoded_payload?

Entirely up to you and what you need.

As for how you handle it, You have a few choices