InvokeClient() Yielding permanently

I have a remote function, and I use InvokeClient() to yield the server code until the Client returns a value. But for some reason, even after the client returns the value the server code doesn’t continue running.

Server Code

local Accepted = SendOffer:InvokeClient(Player, 'Message')
print(2)

Client Code

SendOffer.OnClientInvoke = function(Offer)
	while true do
       if Accepted ~= nil then
          print(1)
          return Accepted
       end
       wait(1)
    end
end

It prints 1 but doesn’t print 2

1 Like

What does ‘accepted’ in your client code refer to??

This is only an example code, the actual code has a variable that gets changed when the player presses a TextButton, so Accepted is originally nil, but gets set to false or true depending on which button the player clicks

All I can say based on what I saw was that your condition never evaluates to true so it’s just an infinite loop.

Can you verify it does become true?

It actually does, I’ve debugged it, it does return the value. The only problem is the server never stops yielding, even after the value is returned

From this code alone, it looks like Accepted is always nil on the client, so the client infinitely waits for something to happen that never happens.

This might be a quirk with BindableFunctions in general—if you use wait() at all, it may not actually send things back to the server? In that case, just go with the suggestion I mentioned below.


Side note:

I would not recommend ever using InvokeClient in server-side code for security reasons. The reason being that an exploiter can wait forever (like in this example), throw an error (breaking the server code), or even just send bogus values back. You should never trust data that the client sends you back outright.

Instead, I would recommend using a RemoteEvent. You can call RemoteEvent:FireClient(Player, 'Message')
to give the client a one-way message, and then listen to this message on the client using RemoteEvent.OnClientEvent:Connect(function(Offer) --[[ ... ]] end)

You can use the same remote (or a different remote, which I would recommend for organization reasons) to then send a message back from the client to the server.

If you want to wait for a message on the server, you can use
local Accepted = RemoteEvent.OnServerEvent:Wait()
or alternatively listen to this message using
RemoteEvent.OnServerEvent:Connect(function(Accepted) --[[ ... ]] end)

I would recommend the second method if at all possible, but this depends on how you structured your code.

4 Likes

You should try breaking the while loop if Accepted exists, then return Accepted at the end of the line

Security isn’t a problem for what I’m doing, if an exploiter never returns a value it won’t impact the server code because the code that Invokes the client is a separate thread created just for this, so that thread can yield forever and it wont impact the code overall, and if the exploiter returns different values it doesn’t matter, because the server will check if the client returned a true Boolean, so if he returns anything else the server code just won’t execute the rest of the code

I could use remote events, but I really want to figure out what’s wrong here, since for this case RemoteFunctions would be much easier to use. I wanna understand if I’m making some kind of mistake or if it’s an engine bug.

Ok, I found out the problem… I was using a custom wait function I have inside the while loop. and idk if that is exactly the problem, but maybe by calling functions inside the Invoked Function it can break it and never return a value to the server? Apparently it’s because my custom function used coroutines, so it doesn’t have anything to do with calling functions

Not 100% sure, but I changed my custom wait function for the roblox API task.wait() and it works now. I appreciate everyone’s help!

1 Like