Cannot resume non-suspended coroutine, DataStore & xpcall()

Since DataStore OnUpdate is broken I have to come up with another way to check for a New Place Version with Datastore so I did, but the problem is that I keep getting this error
cannot resume non-suspended coroutine

I’m not sure why but I think it’s because of the xpcall() see code below

Code
-- PlaceVersion DataStore --
if not RunS:IsStudio() then
	local GameDataStore = DataStoreService:GetDataStore('Name','Scope')
	local Saved_PlaceVersion,Result
	local Default_WaitTime = 60
	local Extra_WaitTime = 0
	local function GetANDCompare_PlaceVersions_Func()
		local Success = pcall(function() Saved_PlaceVersion = GameDataStore:GetAsync("PlaceVersion") end)
		if Success and Saved_PlaceVersion then
			Result = Current_PlaceVersion == Saved_PlaceVersion and 'Lastest_Version' or Current_PlaceVersion < Saved_PlaceVersion and 'Outdated_Version' or Current_PlaceVersion > Saved_PlaceVersion and 'New_Version'
			print('Time',tick())
			return
		end
		wait(Default_WaitTime)
	end
	local function CheckForPlaceVersionUpdate_Func()
		while wait(5) do
			if DataStoreService:GetRequestBudgetForRequestType(1) >= 5 and xpcall(GetANDCompare_PlaceVersions_Func,GetANDCompare_PlaceVersions_Func) then
				if Result == 'Outdated_Version' then
					break
				elseif Result == 'New_Version' then
					GameDataStore:SetAsync("PlaceVersion",Current_PlaceVersion)
					Extra_WaitTime = 600
				elseif Result == 'Lastest_Version' then
					Extra_WaitTime = 300
				end
			end
			print(Result)
			Result = nil
			wait(Default_WaitTime+Extra_WaitTime)
		end
	end
	spawn(CheckForPlaceVersionUpdate_Func)
end

Output >>
https://gyazo.com/61c24d104bf0d0ec03ba46504d981481
https://gyazo.com/4153563d0ac19705cd4b5dd72227c8f0
https://gyazo.com/b28b8717f416c81278a295581415f7da

Testing xpcall() Behavior
local X = 0

local function Err_Func()
	X = X + 1
	print(time())
	error('Hi There')
end

for i = 0, 10 do
	xpcall(Err_Func,Err_Func)
end

print(X)

Output of X >> 2442

You cannot yield in xpcall. Re-implement xpcall as the following:

local function xypcall(successProc, failureProc, ...)
	-- Store it in a table to get all return values
	local call = {ypcall(successProc, ...)}
	
	-- Check if the pcall failed to call the failure proc
	if not call[1] then
		call = {ypcall(failureProc, select(2, unpack(call)))}
		-- If the proc to call when failing errored, return "error in error handling"
		if not call[1] then
			return false, "error in error handling"
		end
		return false, select(2, unpack(call))
	end
	
	return true, select(2, unpack(call))
end

…or if you want to be less verbose than I am, just use ypcall and check if the success return is true or not.

This is not a correct alternative. The main point of xpcall is that the error handler is called just after the error, allowing the handler to retrieve a stack trace via debug.traceback. This is otherwise impossible without using a custom error function to intercept the error beforehand.

pcall also disallows error types other than strings, while xpcall allows anything.

2 Likes

That’s true, although I think my code is good enough for most use cases for it.

Cool I like how you implemented your own xypcall()



I don’t understand the problem tho,

Does xpcall() trigger the Err handler function until it succeeds or just once?

Why does it seems like it’s being triggered a lot? see Testing xpcall() Behavior

We can’t.

> xpcall(function() error() end, function() wait() end)
13:19:59.263 - attempt to call a nil value
13:19:59.423 - cannot resume non-suspended coroutine (x220)
> xpcall(function() wait() end, function() print("im here") end)
im here
13:20:13.145 - attempt to call a nil value

As for the xpcall behavior in your post, I’m not sure.

…I thought I could trust @Crazyman32 I am devastated.

Joking aside, is that a bug or supposed to happen? I thought that Roblox made some changes a few months ago.

Yielding in pcalls (that aren’t ypcall) just seems to be broken in many ways, it’s not documented on the Lua wiki if that’s what you’re asking.

Hmm is that a bug? I know for sure pcall can yield. ypcall was added before that was the case, and then they changed pcall. I see no reason why xpcalls behavior shouldn’t be changed too.

You can yield in a pcall (which means you can change my code to pcall instead of ypcall), but not in an xpcall.

Yes I understand that, but that’s why I would assume that xpcall should behave the same

1 Like