104: Cannot Store Dictionary in DataStore

I am basically trying to save character stats such as the following

local Stats = {
   		CharName = Player:WaitForChild("CharSettings"):WaitForChild("CharacterName").Value,
   		Cash = Player:WaitForChild("Stats"):WaitForChild("Cash").Value,
   		Bank = Player:WaitForChild("Stats"):WaitForChild("Bank").Value,
   		PlayTime = Player:WaitForChild("Stats"):WaitForChild("PlayTime").Value
   	}

   	playerData:SetAsync("Char1Stats"..Player.UserId, Stats)

When I try to do so, I get the following error

104: Cannot store Dictionary in DataStore

My original concept was to save things like this

playerData:SetAsync("Cash"..Player.UserId, Player.Stats.Cash.Value)
playerData:SetAsync("Bank"..Player.UserId, Player.Stats.Bank.Value)
playerData:SetAsync("Playtime"..Player.UserId, Player.Stats.PlayTime.Value)

But I figured this would cause lag and use up the limits on saving in the datastore. However I’ve been running into error 104. What could I do to fix this?

Can you try looping through all of the stats and check if any of them are nil?

a person had this issue not long ago and the cause was a nil value

if you dont want to loop through it you can also turn the dictionary into a json and save the json,
then when you load turn the json into a dictionary again and use that as the data

none of the int values are nil, they are all correct. It just gives an error when trying to save all the data at once using the table

If thats the case then i would recommend turning the dictionary into a json, saving the json string then turning it back when you need to load

use HttpService for this, JSONEncode to turn the dictionary into a json and JSONDecode to turn the json into a dictionary

1 Like

Are any of the stats userdata values such as CFrames or NumberRanges?

1 Like

You can also try doing:

local Stats = {}
Stats.CharName = Player:WaitForChild("CharSettings"):WaitForChild("CharacterName").Value
Stats.Cash = Player:WaitForChild("Stats"):WaitForChild("Cash").Value
Stats.Bank = Player:WaitForChild("Stats"):WaitForChild("Bank").Value
Stats.PlayTime = Player:WaitForChild("Stats"):WaitForChild("PlayTime").Value

That way you can be sure that the script has waited for these values before attempting to save the table.

You can also make checks:

if Stats.CharName and Stats.Cash and Stats.Bank and Stats.PlayTime then
	-- save
else
	-- error handling
end

Yea they are all userdata values

1 Like

Theres your issue, you cannot save userdata values directly (not even in dictionaries)

1 Like

You can’t save userdata values. Go through all of your stats you’re saving, and print(type(stat)). If it prints userdata then you’ll have to save that value differently.

4 Likes

If you’re looking to save Roblox objects, you would need to serialize it’s properties (no official method) and save that table.

What approach would you use to save userdata value through tables? Would turning the dictionary into a json be the most effective?

Shouldn’t be that hard. You could use the new Roblox json API dump to find the right values to read and write.

I would just make a function to serialize the userdata and turn them into tables, and another function to create the userdata from the raw tables. For example, a CFrame serialize:

function serializeCF(cf)
	return {cf:GetComponents()}
end

function makeCFFromRaw(rawCF)
	return CFrame.new(unpack(rawCF))
end

Edit: I don’t know whether this is better than a JSON approach or not, I haven’t looked into it much.

2 Likes

I have a module that handles JSON encoding/decoding dictionaries with userdata support: https://www.roblox.com/library/1005802894/JSON-with-Userdata-Support

4 Likes