Pass msg.payload.property to template in mustaches - Bug?

This template works without error when passed payload "Tuesday" :

<template>
    <div>
        <h2>No errors here</h2>
       <p>Today is {{msg.payload}}</p>
    </div>
</template>

image

But this template gives a console error errorCaptured TypeError: can't access property "dinner", msg.payload is undefined when passed payload

{
    "breakfast": "Croissant",
    "lunch": "Sandwiches",
    "dinner": "Steak"
}
<template>
    <div>
        <h2>Check the console!</h2>
       <p>Dinner will be {{msg.payload.dinner}}</p>
    </div>
</template>

NB the dashboard still shows the desired output
image

It seems like the code is initially parsed before msg.payload has a value, then again when the message arrives. But that doesn't explain why there is no error in the first example.

Is this a bug or deliberate?

There are a bunch of work-arounds. Probably the simplest is to use "Optional chaining" to pass message properties. NB the fallback value (here an empty string) is essential. :

<p>Dinner will be {{msg?.payload?.dinner ?? '' }}</p>

Is there any reason why the ui-template code can't do this optional chaining, or protect the object with v-if, or otherwise, automatically in the background?

It is inevitable. The code has to be interpreted immediately it appears on screen, the template might not have any dynamic content of that sort so might never be sent a message. The reason there is not a problem with msg.something is, I guess, that, due to the way the template widget is coded, an empty msg object does already exist in the browser, ready for a real message to be sent across from the server. Therefore msg.payload is not an error, just undefined. However if you add another level on then the js interpreter throws an error as you are trying to evaluate undefined.dinner. The solution (which is not a workaround, it is just good practice) is use the optional chaining as you suggest. You don't need it on the msg part though, as that does exist.

I am not seeing that. For me it works ok without it.
{{msg.payload?.dinner'}}