Can you use 'xpcall' for Data Stores?

So I have this data store script. It works but I was simply wondering if I could try something different for it. Here’s the script:

local DSS = game:GetService("DataStoreService")
local DataStore = DSS:GetDataStore("PlayerData")

local function saveData(player)
	
	local Table = {player.leaderstats.Coins.Value}

	local success, errormessage = pcall(function()
		DataStore:SetAsync(player.UserId, Table)
	end)

	if success then
		print("Successfully saved your data!")
	else
		print("An error occurred while saving your data. Please try again later.")
		warn(errormessage)
	end
	
end

game.Players.PlayerAdded:Connect(function(player)
	
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local coins = Instance.new("IntValue")
	coins.Name = "Coins"
	coins.Parent = leaderstats
	coins.Value = 0

	local data
	local success, errormessage = pcall(function()
		data = DataStore:GetAsync(player.UserId)
	end)

	if success and data then
		coins.Value = data[1]
		print("Successfully found your data")
		print(DataStore, data)
	else
		print("We couldn't find any data for you.")
		warn(errormessage)
	end
	
	while wait(120) do
		saveData(player)
	end
	
end)

game.Players.PlayerRemoving:Connect(function(player)
	saveData(player)
end)

game:BindToClose(function()
	for _, player in pairs(game.Players:GetPlayers()) do
		saveData(player)
	end
end)

What I’m want to do for the script is to replace the regular protected call. I’m just asking if it’s possible to use xpcall() instead of pcall() for the script.

1 Like

You can, it will just be equivalent to moving your else cases into a function, like:

-- Before
local success, res = pcall(...)

if success then
    -- handle success
else
    -- handle error
end

-- After
local success, res = xpcall(..., function (err)
    -- handle error
end)

if success then
    -- handle success
end
2 Likes

Thanks but a quick question, what is the ... in xpcall() supposed to be DataStore:SetAsync(player.UserId, Table) or should that be placed somewhere else?

... in my code was meant to be the function that you want to run in protected mode. Works exactly the same as pcall.

local success = xpcall(function()
	DataStore:SetAsync(player.UserId, Table)
end, function (err)
    -- handle error
end)

Oh, ok. Thanks for clarification.

I understand this thread was solved, but I have a few bits of additional knowledge that may be pertinent to offering historical clarity.

There was a very lengthy span of time that xpcalls could not yield, but that has since changed (see the Luau Recap for March 2020); it’s now valid to use xpcall for these purposes. However, there still persists one notable caveat, in that the catching function (the one handling the error), is still incapable of yielding. As such, the catching function should not be used to make any further calls to datastores, or any other yielding functions for that matter.

3 Likes