Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters

Edit: Solution at the very end.

I get an error message:
DataStoreService: CantStoreValue: Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters. API: SetAsync, Data Store: dataStore

What in the screenshot does it not like? Is there a way to write some code to tell me where I have the things it doesn’t like?

Bonus question: Any way to round the custom physical properties numbers and angular velocity numbers?

Thanks!

Is the cframe actually a cframe or is a table full of numbers?


this is how it’s being saved. Should I put a “tostring” in front of everything that’s not a boolean?

You can only save tables, strings, numbers, booleans, and recently buffers, and even then it’s automatically (de)serialized by Roblox.

CFrame, CustomPhysicalProperties, Shape and Material, and maybe Color, are the likely problematic ones.

CFrame can just be saved as a Position and rotation, Shape and Material as a number, Color as an array (or maybe a single number with bit32), and CustomPhysicalProperties as a dictionary.

1 Like

If this is a problem with showing them on GUIs, then you can use string.format("%.2f", number) to round it to 2 decimal places.

1 Like

That sucks… I’ll hopefully reply in a day, once I rewrite everything :sob:
I already did the deserialization, so I have to rewrite that too…

1 Like

So far I have this:

Scale = item.Scale – doesn’t like (gives an error)

Scale = { X = item.Scale.X, Y = item.Scale.Y, Z = item.Scale.Z } – likes (no error)


Update

Whats with all the string manipulation stuff to get the material and shape? Just do something like this:

BasePart.Material.Name -- For name
BasePart.Shape.Name -- For shape

Otherwise, the other stuff looks good to me

1 Like

Thank you! It works :smiley:

30 chАrаcters

Honestly, your previous idea of saving the numbers as strings might be more efficient to store than tables. For example, if you tostring’ed a BasePart’s color it would be “1, 1, 1” and to turn it back to its original values you could tonumber these numbers after using string:Split on it

What do you think I should prioritize? Performance or Internet usage? My entire “game” is on a local script, so loading in and saving is the only time a server script is needed. I also want my friend to be able to play on his late 2000s ThinkPad :joy:

Waiting for something to load for 2 extra minutes doesn’t seem that bad imo… So I’m thinking to prioritize performance at the cost of datastorage size. But please, provide a counterargument so I can decide best :smiley:

I just wanna chime in here. Instead of saving the color as an array, why not save it as a HexValue instead? ToHex() returns a string of a colors hex value.

dataTable = {
    ["Color"] = item.Color:ToHex()
}

And then when the parts color is to be set,

local dataTable = loadedDataTableHere

item.Color = Color3.fromHex(dataTable["Color"])
2 Likes

For your entire game, you should prioritize performance. If your entire game is client-sided, then there isn’t a lot of information being sent from their server to the client, so there won’t be that much traffic. Also, data saving has nothing to do with how long the client takes to load because it’s on the server and generally doesn’t take long.

Overall, I mentioned you should think about the most efficient way to save data because roblox’s data stores have limits. Also, the larger the data the longer it takes to get it. Now let’s get technical.

Dictionaries usually take more space than basic data types such as strings, booleans, and numbers because they’re more complex so using strings will help a lot.

I would personally do this for Vector3 and CFrame data types:

local BasePlate = workspace.Baseplate

local Data = {
	Position = tostring(BasePlate.Position),
	Size = tostring(BasePlate.Size),
	Orientation = tostring(BasePlate.Orientation)
}

local function Convert(DataString:string) 
	local Split = DataString:split(", ")

	local Result = {}

	for Index, Value in Split do
		local Number = tonumber(Value) 

		if not Number then
			warn(`Index of [{Index}] has been automatically converted to 0.`)
			Number = 0 
		end

		table.insert(Result, Number)
	end

	return table.unpack(Result)
end

local Position = Vector3.new(Convert(Data.Position))
local Size = Vector3.new(Convert(Data.Size))
local Orientation = Vector3.new(Convert(Data.Orientation))

W this works

30 сhаrасtеrs

1 Like

Looks great!

One question though:
You have an edge case at lines 19 through 22
When would this edge case be needed?

Otherwise, perfect, I’ll be using this too! My God, y’all are on fire! I’m so thankful I made a forum post :smiley:

You’re right. The scenario in which the string is not a perfect number is extremely unlikely. You don’t need the check; I just have a habit of expecting the unexpected.

Edit: Also, I think strings are good because they don’t lose information, unlike numbers. When saving numbers with decimals I think datastores round it off making you lose precision.

1 Like

Interesting :joy:
This is like my second time coding this month (I’ve been coding on and off for like 3 years now though), so I’m not too experienced, hence why I’m receiving all the help I can get :stuck_out_tongue:
Maybe I’ll get into that habit after some time, who knows :smiley:

Awesome! I’ll be including everybody’s code! Thank you all so much! But now I don’t know who to mark as the solution… :rofl:

Just pick the reply that you feel helped you the most so that others can know the problem has been solved