RemoteEvent fires before :connect returns

RemoteEvents fire before the :connect method returns. I expect :connect to return so I have a RbxScriptConnection before the RemoteEvent code is fired.

This happens every time on WWW and is not game or level specific. I have only tested it in Studio.

This only occurs when there is an event in the queue waiting to be picked up by a connection on the other side.

I noticed this bug yesterday.


Repro: CallTooSoonRepro.rbxl (12.5 KB)
See the script in ServerScriptService that tried to disconnect conn when OnServerEvent is fired.

6 Likes

:connect is deprecated, use :Connect. This could be what’s causing your problem.

1 Like

Deprecation in this case (and in general) does not change behavior – connect/Connect behave the same.

I can confirm the broken behavior.

--client fires ReplicatedStorage.RemoteEvent during this time
wait(10)

local conn
conn = game.ReplicatedStorage.RemoteEvent.OnServerEvent:connect(function()
	conn:disconnect()
end)

The expected behavior is that the connection will disconnect after OnServerEvent invokes the passed function, but conn:disconnect() actually errors with attempt to index conn a nil value because the passed function is being invoked before the connection has finished being set up and sets the conn variable. Removing the wait resolves the issue.

3 Likes

You’re touching on a larger issue. RemoteEvents are flawed in the following way: interacting with the RemoteEvent’s signal (i.e. via Connect or Wait) can cause the signal the fire. This has several implications:

  • Only the first connected listener will receive any queued events.
  • Multiple threads cannot use Wait without missing queued events.
  • Wait and Connect cannot be mixed: Wait receives queued events one at a time, but a single Connect will drain the entire queue, leading to Wait missing queued events.

More generally, in any case where a signal is fired via its own Connect or Wait method, one cannot reliably use multiple Connects and Wait at the same time. Other than RemoteEvents, no other signal has this behavior. Also consider that there are no APIs that allow Connect or Wait to be “listened in” on. Based on all this, one could conclude that being unable to listen in on signals like this is a necessary feature in how signals are designed, one which RemoteEvents have violated.

I think the best solution is to remove the automatic dequeuing behavior, and instead add a method to RemoteEvent that dequeues and returns a list of any queued events. This will require developers to handle queued events explicitly, but it will give them time to setup listeners. More importantly, RemoteEvents will no longer violate signal design.

For now, in order to use a RemoteEvent safely, it should have at most one listener, or one thread handling Wait.

19 Likes

This behavior is only really encountered when doing weird things. If the remote is created and listened to server side then it should be created way before any client is even ready to fire it.

In any case, the client should send a signal to the server saying “I’m ready” once it loads through one of your remotes so you know it can fire and receive now. This solves the issue on both ends and is ideally how one should go about this async stuff.

I’m aware of ways to solve this – most of my Remotes have a single connection. Here, I was being lazy and discovered buggy behavior. Regardless of the best practices, an event should not fire before :connect returns.

As to why I was doing this, I was being a bit lazy: this event should only accept being fired once, and I don’t want to have to keep track of players in a table and add/remove them when they join/leave. Instead, I connected to the event when the player is allowed to fire it and removed the connection when they’ve fired it.

Bumping this 4 years old issue, because I confirm that it is still happening. It is in fact very annoying, as you have to yield before being able to disconnect.

1 Like

Hello! Thank you for the report. The original script provided as a repro doesn’t exist any longer (understandably) though I have tried to do so on my end based on the snipped provided here but was unable to repro it either.

Does the issue still exist or has it been resolved?

It is still reproducible; but only when the signal behavior is set to Immediate, rather than the now default Deferred.

Here’s a new repro file I threw together
RemoteEventRepro.rbxm (2.2 KB)

Gotcha, deferred events would be my recommendation to workaround this issue especially as that is our preferred default behavior for events.

1 Like