Coroutine.yield does not allow ModuleScript to return

Hello developers, today I think I found a bug. I was working on a project when I added a certain snippet of code that locked everything. After a lot of debugging, I was able to narrow down the problem to coroutine.yield, and I separated the code into a separate script to test it without any interference. These are the two scripts in their entirety:

Script:

local result = require(script.Parent:WaitForChild("ModuleScript"));

print(result); --This does not print.

ModuleScript:

local thread = coroutine.running();

task.spawn(function()
	task.wait(1);

	coroutine.resume(thread);
end);

coroutine.yield();

return "Why doesn't this return?", print("This is printing, for some reason"); --This does print, I am only adding the print here for testing reasons

As you can see this is a simple test, there is a separate task that waits one second, to then resume the paused coroutine. Normally, someone would assume that the problem is before the return statement. But the This is printing, for some reason message prints to the console, which gives us the knowledge that the return statement is running. For some reason, the script never receives the result, and as such, halts its entire execution.

Does someone know why, or if this is a bug?

Edit: For those wondering why I couldn’t just ditch task.spawn entirely and use task.delay, it’s because inside task.spawn there is code running that doesn’t allow me to just replace everything.

I came up with a solution for my problem, if you want to check it it’s this message: Coroutine.yield does not allow ModuleScript to return - #4 by STORMGAMESYT7IP

coroutine.yield doesn’t accept a thread to be yielded, only arguments that will be passed the next time you resume the thread. I believe in the print’s case, it’s already being evaluated for the return value which is just going to be void anyway because print doesn’t return anything.

In any case: the task library is also able to resume threads so you can just directly pass the acquired thread from coroutine.running as an argument to task. Additionally, you should use task.delay rather than waiting at the start of a spawned thread, it’ll do the same thing in one function.

local thread = coroutine.running()

task.delay(1, thread)

coroutine.yield()

return "This returns"

You did find a bug though. Check out this bug report and its discussion.

In short: the answer is to not use coroutine.resume.

1 Like

Thank you for pointing out the mistake in courotine.yield, I forgot it didn’t need an argument. (for those wondering the reason it didn’t have an impact is that courotine.yield thought the thread was a message).

In case of the print, the reason I added it to the return message is precisely for what you said. If it is evaluated for the return and it prints, then that means the return keyword is running. So I only added it there to test that.

In regard to task.delay, the reason I can’t use task.delay is because in my actual script (the one I took this error from), there is code executing between coroutine.resume and coroutine.yield. To be more precise it is a promise, so that’s why I can’t use task.delay for the actual use case. However, you are completely right about using it for this example.

1 Like

For those wondering, based on @colbert2677 answer and linked post, I came up with this solution:

local thread = coroutine.running();

task.spawn(function()
	task.wait(1);
	
	--Let's assume some stuff goes here.
	
	if (coroutine.status(thread) == "suspended") then --Add this to prevent errors (if the coroutine is still running, then it will spawn twice and cause things to mess up)	
		task.spawn(thread);
	end
end);

coroutine.yield();

return "This is working.", print("This is printing as well");

Just by replacing coroutine.resume with task.spawn the script functions normally.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.