DataStoreService fails my :SetAsync() request

DSS seems to not want to save a table containing information on a player’s inventory.

This script is connected to a PlayerRemoving event:

local PlyrStuff
	
	local s, failure = pcall(function()
		PlyrStuff = getStore:GetAsync("Plyr_"..Player.UserId)
	end)
	
	if s then
		print(s)
		print(PlyrStuff)
	elseif failure then
		warn("Error will trying to process person's items!")
	end
	
	--Clear hair/Accessories list
	for i, v in pairs(PlyrStuff.Hairs) do
		table.remove(PlyrStuff.Hairs, i)
	end
	
	for i, v in pairs(PlyrStuff.Addons) do
		table.remove(PlyrStuff.Addons, i)
	end
	
	--Begin process yay
	for i, v in pairs(Player.PlyrItems.Passes:GetChildren()) do --Passes
		if v.Value == true then
			PlyrStuff.Gamepasses[v.Name] = v.Value
		end
	end
	
	local Clothes = Player.PlyrItems.Clothes --Clothes
	PlyrStuff.Clothes.Shirt = Clothes.Shirt.ShirtTemplate
	PlyrStuff.Clothes.Pants = Clothes.Pants.PantsTemplate

	for i, v in pairs(Player.PlyrItems.Hairstyles:GetChildren()) do -- Hairs
		if v:IsA("Accessory") then
			PlyrStuff.Hairs["Hair_"..v.Name] = v.Name
			PlyrStuff.Hairs[v.Name.."Colour"] = v.Handle.Color
		end
	end
	
	for i, v in pairs(Player.PlyrItems.Accessories:GetChildren()) do --Accessories
		if v:IsA("Accessory") then
			PlyrStuff.Addons["Addon_"..v.Name] = v.Name
			PlyrStuff.Addons[v.Name.."Colour"] = v.Handle.Color
		end
	end
	
	local Weapon = Player.PlyrItems:FindFirstChildOfClass("Model")
	local Ability = Player.PlyrItems.Ability
	
	PlyrStuff.Combat["Weapon"] = Weapon.Name
	PlyrStuff.Combat["Ability"] = Ability.Value
	
	local success, fail = pcall(function()
		return getStore:SetAsync("Plyr_"..Player.UserId, PlyrStuff)
	end)
	
	if success then
		print(success)
	else
		warn("An error occurred trying to save this person's items. Oops!")
	end

Leaving the game, the output bar gave me the warning:

I’m a little confused as to why it rejected the table, as nothing I have within it contains an instance in the workspace.

Make sure to verify s == true instead of just seeing if s isn’t nil!

This allows for more flexibility, and you can make sure youre if statement is being handled correctly

if s==true then
		print(s,PlyrStuff)
	elseif s == false then
		warn("Error will trying to process person's items! : "..(failure~=nil and failure or "Unknown"))
end

Thanks, I switched it to that, but this didn’t seem to fix the problem

1 Like

I just edited my message, try to comment out the old line and replace it with that

Also at the end, make sure to change

if success then

to:

if success == true then

The entire pcall function completely halts the event now. What is going on?!

Take a look:

Players.PlayerRemoving:Connect(function(Player)
	print(Player)
	local playerTeam = Player.Team
	--Must update values!
	if playerTeam == Red then
		RedValue.Value = RedValue.Value - 1
		for i, v in pairs(tellTeam.Red) do
			if v == Player.Character then
				table.remove(tellTeam.Red, i)
			end
		end
	elseif playerTeam == Blue then
		BlueValue.Value = BlueValue.Value - 1
		for i, v in pairs(tellTeam.Blue) do
			if v == Player.Character then
				table.remove(tellTeam.Blue, i)
			end
		end
	end
	
	--You should probably do DSS here
	local PlyrStuff
	
	local s, failure = pcall(function()
		PlyrStuff = getStore:GetAsync("Plyr_"..Player.UserId)
	end)
	
	print(PlyrStuff) -- It doesn't print this at all? The commands don't seem to be firing past this point now
	if s == true then
		print(s)
		print(PlyrStuff)
	elseif s == false then
		warn("Error while trying to process person's items!")
	end
	
	--Clear hair/Accessories list
	for i, v in pairs(PlyrStuff.Hairs) do
		table.remove(PlyrStuff.Hairs, i)
	end
	
	for i, v in pairs(PlyrStuff.Addons) do
		table.remove(PlyrStuff.Addons, i)
	end
	
	--Begin process yay
	for i, v in pairs(Player.PlyrItems.Passes:GetChildren()) do --Passes
		if v.Value == true then
			PlyrStuff.Gamepasses[v.Name] = v.Value
		end
	end
	
	local Clothes = Player.PlyrItems.Clothes --Clothes
	PlyrStuff.Clothes.Shirt = Clothes.Shirt.ShirtTemplate
	PlyrStuff.Clothes.Pants = Clothes.Pants.PantsTemplate

	for i, v in pairs(Player.PlyrItems.Hairstyles:GetChildren()) do -- Hairs
		if v:IsA("Accessory") then
			PlyrStuff.Hairs["Hair_"..v.Name] = v.Name
			PlyrStuff.Hairs[v.Name.."Colour"] = v.Handle.Color
		end
	end
	
	for i, v in pairs(Player.PlyrItems.Accessories:GetChildren()) do --Accessories
		if v:IsA("Accessory") then
			PlyrStuff.Addons["Addon_"..v.Name] = v.Name
			PlyrStuff.Addons[v.Name.."Colour"] = v.Handle.Color
		end
	end
	
	local Weapon = Player.PlyrItems:FindFirstChildOfClass("Model")
	local Ability = Player.PlyrItems.Ability
	
	PlyrStuff.Combat["Weapon"] = Weapon.Name
	PlyrStuff.Combat["Ability"] = Ability.Value
	
	local success, fail = pcall(function()
		return getStore:SetAsync("Plyr_"..Player.UserId, PlyrStuff)
	end)
	
	if success == true then
		print(success)
	elseif success == false then
		warn("An error occurred trying to save this person's items. Oops!")
	end
end)

In one line I told the script to print PlyrStuff, and it won’t print that at all now. The pcall seems to just halt the event entirely.

You may print the error message if it couldn’t proceed the function so that we can learn what’s going on with the script.

warn(fail)

@boxrum

You don’t need to assign the s variable to the equivalence of nil because that always returns true or false -in accordance with pcall.

So if and elseif statements look for the given match. Unless the match returns nil or false, the if statement continues the code written inside it. You don’t need to use another bool.

if success then --is equivalent

-- to

if success == true then
2 Likes

In this case, you should also print the error message it returned in the output to know exactly why it is erroring. In the case of pcall returning an unsuccessful execution (success variable is false), pcall returns another value which represents the error message, so you can do:

warn("An error occurred trying to save this person's items. Oops! Error message" .. fail)

Just to point out other problems in your code, you’re saving the hats and addons in their respective tables with strings as the indices. The thing is when the time has come to remove the hats, using table.remove will not work. table.remove expects the second argument to be a number and using a string will cause it to error. You can hold the name just in the entry’s value and make the indices number so that it becomes an array using table.insert which will append the value to the end of the table with a numeric index

As to why it doesn’t work, you’re attempting to save a Color3 which is a userdata that cannot be saved in datastore. What you can do is serialise the data when saving, meaning you represent the data in a form that can be saved. What you can do is create a dictionary containing the color3’s components:

-- example:
local colour = v.Handle.Color
table.insert(PlyrStuff.Hairs, {Name = v.Name, r = colour.R, g = colour.G, b = colour.B})

When you want to set the colour back, you will have to deserialise the table, meaning you will construct the userdata from the serialised data:

-- this is just an example, not actual code:
local hatInfo = PlyrStuff.Hairs[1]
Hat.Color = Color3.new(hatInfo.r, hatInfo.g, hatInfo.b)
1 Like

Thanks for the input. It brought me a big step forward into learning DataStoreService as this is my first time actually utilizing it.

I’ve changed everything to how you’ve said it, and I’ve also streamlined the code a bit to not use table.remove. I’m still running into a very funky problem that I can’t seem to understand:

Past the line of code in the pcall(), absolutely nothing else will run:

	--You should probably do DSS here
	local PlyrStuff
	
	local s, failure = pcall(function()
		print("Beginning")
		PlyrStuff = getStore:GetAsync("Plyr_"..Player.UserId)
	end)
	
	if s then
		print(s)
		print(PlyrStuff)
	else
		warn(failure)
	end

image
Nothing else beyond this will print, which tells me no line of code is registered past this point

EDIT: It’s working now. Thanks for the help!

What is getStore? You don’t seem to specify what it is.
Also, little trick with pcalls.

local fired, err = pcall(getStore.GetAsync, getStore, "Plyr_" .. Player.UserId)
-- A.B(A) with respect to self in A:B()

You could try a one line pcall, but also, pcalls can return values as they are callbacks. So you don’t need a whole new variable for player stuff.

local fired, PlyrStuff = pcall(function()
  return getStore:GetAsync("Plyr_" .. Player.UserId) 
end)

getStore is the DataStore that is called in my script.

local DSS = game:GetService("DataStoreService")
local getStore = DSS:GetDataStore("Inventory")

Would this pcall method fix the issue where my code is being halted? If you saw my other replies my final issue seems to be that the script does not operate beyond the first pcall function that is called in the script.

EDIT: Code works now. Thanks for the help.