Is msg.post to a non-existent game object or component supposed to return without error? (SOLVED)

When I msg.post to non-existent game objects or components using a protected call (e.g. local ok, _ = pcall(msg.post, "default:/bad#url, "some_message")), no error is caught (pcall returns true) even though I see ERROR:GAMEOBJECT console output complaining that the URL could not be found. However, posting to a non-existent socket throws an error pcall can catch (pcall returns false). Is this how it’s supposed to work, or am I doing something wrong?

I’m a Defold novice working my way through the “What next?” section of the ColorSlide tutorial and, in playing with the case where the player completes the last level and there is no “next” one (exercise 4), came across a suggestion to use pcall to detect when the msg.post fails (because it’s directed at the non-existent proxy for level 5): [SOLVED] Checking collection exists before proxy loading - #2 by Mathias_Westerdahl I also saw a (much older) post suggesting that a msg.post to a bad URL should throw an error that’s caught in protected mode: Defold doesn't show any error and stop execution of the сoroutine if you wrongly send message from module msg.post (SOLVED) - #10 by britzl

To reproduce:

  1. Check out the tutorial-done branch of ColorSlide (GitHub - defold/tutorial-colorslide at tutorial-done)
  2. In loader.script’s on_message, wrap the msg.post(proxy, "load") in a protected call like so:
function on_message(self, message_id, message, sender)
	if message_id == hash("load_level") then
		self.current_level = message.level
		local proxy = "#proxy_level_" .. self.current_level
		-- msg.post(proxy, "load")
		local ok, _ = pcall(msg.post, proxy, "load")
		if ok then
			print("Pcall msg.post to " .. proxy .. ": OK.")
		else
			print("Pcall msg.post to " .. proxy .. ": NOT OK.")
		end
  1. Run the game and select level 4. The console output reads:
DEBUG:SCRIPT: Pcall msg.post to #proxy_level_4: OK.
  1. Clear level 4 (or cheat by binding an input to trigger the “Well done!” popover, like I did :winking_face_with_tongue: ), then click the “Next >” button. The console output reads:
DEBUG:SCRIPT: Pcall msg.post to #proxy_level_5: OK.
ERROR:GAMEOBJECT: Component '/loader#proxy_level_5' could not be found when dispatching message 'load' sent from default:/loader#loader

Given the two forum replies above, I thought that ok would be false since the message dispatch failed, but instead it’s true.

Experimentation shows that posting to a nonexistent object within an existing socket does the same…

DEBUG:SCRIPT: Pcall msg.post to default:/nonexistentobject#nonexistentcomponent: OK.
ERROR:GAMEOBJECT: Instance '/nonexistentobject' could not be found when dispatching message 'load' sent from default:/loader#loader

…but posting to a nonexistent socket does throw an error the pcall can catch:

DEBUG:SCRIPT: Pcall msg.post to nonexistentsocket:/nonexistentobject#nonexistentcomponent: NOT OK.

Is this how it’s supposed to work? Apologies if this is addressed in the docs or somewhere else on the forum – I looked but couldn’t find anything definitive, and I’m afraid pulling an answer out of the engine’s source is presently beyond me.

(All above done on Defold 1.10.0 stable on macOS x86_64, installed via the .dmg from GitHub’s releases page.)

This is a very old function, and I don’t know all the design decisions behind its implementation.
While it does seem to check the socket (i.e. the collection name) when posting, it seems the verification of the receiver is done once the message is dispatched on the receiving end (gameobject.cpp).

At this point, we’re likely not making any major changes to that function, as it would likely break a lot of existing games.

As usual, it’s beneficial to look at the source:

Thank you for replying so quickly, and for showing where in the source is responsible for dispatch.

Makes sense, given the way responsibilities seem to be laid out; I can live with that.

If I may ask another novice question: Since pcall can’t tell us in this kind of situation, is there any way for the sending code to know whether the message was rejected at the receiving socket’s end, or are human eyeballs on the console/logs the only way?

we did recently also add go.exists() to check if a game object exists, if that helps.

But also, in general, we also rely a lot on the fact that you probably already knows which objects do or don’t exist. Shouldn’t really require the go.exists() in most circumstances.

2 Likes