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

Trying to make a datastore system with tables, got this error when it tried to save.

local plrs = game:GetService("Players")
local dss = game:GetService("DataStoreService")
local maindata = dss:GetDataStore("TestData")

local dataset = {
	["level"] = 1,
	["rank"] = 1,
	["cash"] = 0,
	["layer"] = 0,
}

plrs.PlayerAdded:Connect(function(plr)
	local data = nil
	
	local leaderstats =  Instance.new("Folder", plr)
	leaderstats.Name = "PlayerData"
	
	for n,v in pairs(dataset) do
		if tonumber(v) then
			local dataval = Instance.new("NumberValue", leaderstats)
			dataval.Name = n
		end
		
		local s,e = pcall(function()
			data = maindata:GetAsync("user-"..plr.UserId)
		end)
		
		if s then
			print("Data loaded for: "..plr.Name)
		elseif e then
			warn("Data did not load for: "..plr.Name)
		end
		
		if data then
			for n,v in pairs(data) do
				plr.PlayerData[n].Value = v
			end
			print("Data loaded for: "..plr.Name)
		else
			print("New playerdata created for: "..plr.Name)
		end
	end
end)

plrs.PlayerRemoving:Connect(function(plr)
	local data = {}
	
	for n,v in pairs(plr.PlayerData:GetChildren()) do
		table.insert(data,v)
		data[v.Name] = v.Value
		print(unpack(data))
		
		maindata:SetAsync("user-"..plr.UserId, data)
	end
end)

Not sure what went wrong, maybe it’s with the dataset part?

You are inserting the objects which are inside PlayerData folder instead of the name, which throws an error. Instead of using table.insert just directly index the data table as you do here.

Works but, there is one problem, only the layer value saves for some reason, the other values do not. How do I fix this?

Move this outside of the for loop (below), you are saving only one value every time it loops instead of just saving after inserting all data.

The issue seems to be with the way the data table is being constructed in the PlayerRemoving event. The data table is being created as an array, but then values are being added to it as if it was a key-value pair table.

Additionally, the data table is being inserted into itself as an array and then added to the DataStore. This will likely result in unexpected behavior and errors.

To fix this, you could modify the PlayerRemoving event to properly construct the data table as a key-value pair table and then add it to the DataStore.

exampleCode for PlayerRemoving

plrs.PlayerRemoving:Connect(function(plr)
    local data = {}

    for _, child in pairs(plr.PlayerData:GetChildren()) do
        if child:IsA("NumberValue") then
            data[child.Name] = child.Value
        end
    end

    local success, result = pcall(function()
        maindata:SetAsync("user-"..plr.UserId, data)
    end)

    if success then
        print("Data saved for: "..plr.Name)
    else
        warn("Data failed to save for: "..plr.Name, result)
    end
end)

In this updated version, we only add NumberValue children to the data table, and we construct data as a key-value pair table. We also wrap the SetAsync call in a pcall block to catch any errors that may occur when saving the data to the DataStore.