Cannot Store Dictionaries

So I have been debugging for almost an hour now and nothing seems to be going good for me and here is the problem

There was an unexpected error, Error:  104: Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters.

and here is the full code

-- Stats Service
-- Username
-- November 18, 2020



local StatsService = {Client = {}}

local PlayerDataSample = {
	Stats = {
		Coins = 0;
		Level = 1;
		EXP = 0;
		MaxEXP = 50;
		Class = "Mage"; -- {Mage, Warrior, Tank}
		Quests = 0;
		MaxQuests = 5; -- maximum is 5
		Rank = "Rookie";
		DoubleSword = false;
		Banned = false;
		SpellPoints = 1;
		PhysicalPoints = 1;
		Stamina = 1;
	};

	SetUp = {
		Helmet = "none";
		Armor = "none";
		Pants = "none";
		Boots = "none";
		Sword = "none";
		DualSword = "none"
	};

	Equipment = {
		Armors = {
			Chestplates = {

			};

			Helmets = {

			};

			Pants = {

			};
		};
	};

	Tools = {
		Potions = {

		};

		Weapons = {
			["Wooden Sword"] = {
				Path = game.ServerStorage.Items.Weapons.Warrior["Wooden Sword"];
				Damage = 1;
				ClassFor = "Warrior";
				Type = "Sword";
				Rarity = "Common";
				ChanceToGet = 100;
				Physical = 1;
				Spell = 1;
				Upgrades = 0;
				MaxUpgrades = 15;
				Debounce = false;
				CanDamage = false;
				IsTradeable = false;
			}
		};
	};

	Spells = {
        --[[
        ["SPELL_NAME"] = {
            Class = "Mage";
            BaseDamage = 0;
            LevelRequired = 0;
            SellAmount = 0;
            Rarity = "Common";
            ChanceToGet = 0;
            SellAmount = 0;
            IsTradeable = false;
        }
        ]]
	};

	Quests = {
		-- for examples only
        --[[
            ["QuestName"] = {
                IsCompleted = false;
                XPWorth = 0;
                CoinsWorth = 0;
                QuestDescription = "Kill 1 Thing";
                ThingsDone = 1;
                IsFromNPC = "nil"
            }
        ]]
	}
}

local BannedPlayers = {} -- FerbZides name is for testing to see if it actually works

function StatsService:Start()
	-- Services
	local HttpService = game:GetService("HttpService")
	local ServerStorage = game:GetService("ServerStorage")

	-- Data Module
	local DataModule = self.Modules.Data

	-- Direct Path to Objects
	-- Forking it

	-- functions

	local function KickPlayer(Player)
		local Data = DataModule.ForPlayer(Player)

		local success, PlayerData = Data:Get("PlayerData", PlayerDataSample):Await()
		if (success) then
			print("Data was Successfully Retrieved!")
		else
			warn("Failed to Retrieve Data!")
		end

		spawn(function()
			if BannedPlayers[tostring(Player.Name)] then
				Player:Kick("You are permanently Banned from this game, you are not welcome.")
			elseif PlayerData.Stats.Banned == true then
				Player:Kick("You are permanently Banned from this game, you are not welcome.")
			else
				print(Player.Name.." is authorized for this game!")
			end
		end) 
	end

	local function PlayerAdded(Player)
		print("Loading Data for "..Player.Name)

		local Data = DataModule.ForPlayer(Player)

		local PlayerDataFolder = Instance.new("Folder", Player)
		PlayerDataFolder.Name = "PlayerData"

		local Stats = Instance.new("Folder", PlayerDataFolder)
		Stats.Name = "PlayerStats"

		local Quests = Instance.new("Folder", PlayerDataFolder)
		Quests.Name = "Quests"

		local success, PlayerData = Data:Get("PlayerData", PlayerDataSample):Await()
		if (success) then
			print("Data was Successfully Retrieved!")
		else
			warn("Failed to Retrieve Data!")
		end

		KickPlayer(Player)

		for Name, Val in pairs(PlayerData.Stats) do
			if type(Val) == "number" then
				local Value = Instance.new("NumberValue")
				Value.Name = Name
				Value.Value = Val
				Value.Parent = Stats
			elseif type(Val) == "string" then
				local Value = Instance.new("StringValue")
				Value.Name = Name
				Value.Value = Val
				Value.Parent = Stats
			elseif type(Val) == "boolean" then
				local Value = Instance.new("BoolValue")
				Value.Name = Name
				Value.Value = Val
				Value.Parent = Stats
			end
		end

		-- Load Tools table, gonna refork this a bit so yeah
		for _, Tools in pairs(PlayerData.Tools) do
			-- Player Backpacks
			local PlayerStarterGear = Player.StarterGear
			local PlayerBackpack = Player.Backpack

			-- loop all the table
			-- {Weapons, Potions} the only things that can be used as tools
			-- loop all the items inside it

			for ToolName, ToolValue in pairs(Tools) do
				local Tool = ToolValue.Path:Clone()
				Tool.Parent = PlayerStarterGear

				local ValuesFolder = Instance.new("Folder")
				ValuesFolder.Name = "Values"
				ValuesFolder.Parent = Tool

				for ToolValueName, ToolsValue in pairs(ToolValue) do
					if type(ToolsValue) == "number" then
						local Value = Instance.new("NumberValue")
						Value.Name = ToolValueName
						Value.Value = ToolsValue
						Value.Parent = ValuesFolder
					elseif type(ToolsValue) == "string" then
						local Value = Instance.new("StringValue")
						Value.Name = ToolValueName
						Value.Value = ToolsValue
						Value.Parent = ValuesFolder
					elseif type(ToolsValue) == "boolean" then
						local Value = Instance.new("BoolValue")
						Value.Name = ToolValueName
						Value.Value = ToolsValue
						Value.Parent = ValuesFolder
					end
				end
			end
		end

		-- get quests
		for Name, Values in pairs(PlayerData.Quests) do
			local QuestFolder = Instance.new("Folder", Quests)
			QuestFolder.Name = Name

			for Name, Val in pairs(Values) do
				if type(Val) == "number" then
					local Value = Instance.new("NumberValue")
					Value.Name = Name
					Value.Value = Val
					Value.Parent = QuestFolder
				elseif type(Val) == "string" then
					local Value = Instance.new("StringValue")
					Value.Name = Name
					Value.Value = Val
					Value.Parent = QuestFolder
				elseif type(Val) == "boolean" then
					local Value = Instance.new("BoolValue")
					Value.Name = Name
					Value.Value = Val
					Value.Parent = QuestFolder
				end
			end
		end

		-- get data characters of the player
		local TableToString = HttpService:JSONEncode(PlayerData)
		print(Player.Name.."'s Data Characters were "..string.len(TableToString))

		print("Succesfully Got Data from "..Player.Name)
	end

	local function PlayerRemoved(Player)
		local Backpack = Player.Backpack
		local Data = DataModule.ForPlayer(Player)

		local success, PlayerData = Data:Get("PlayerData", PlayerDataSample):Await()
		if (success) then
			print("Data was Successfully Retrieved!")
		else
			warn("Failed to Retrieve Data!")
		end


		Data:Save("PlayerData"):Then(function()
			print(Player.Name.."'s Data was Saved!")
		end):Catch(function(err)
			warn("There was an unexpected error, Error: ",err)
		end):Finally(function()
			print("Data handling on "..Player.Name.." was Successful!")
		end)
	end

	game.Players.PlayerAdded:Connect(PlayerAdded)
	game.Players.PlayerRemoving:Connect(PlayerRemoved)
end


function StatsService:Init()

end


return StatsService

but this thing I am just thinking of how to serialize path’s!

so my question is how do you serialize this?

game.ServerStorage.Items.Weapons.Warrior["Wooden Sword"];

Could you try just saving the name of the instance? I save just the names of tools and that usually works for me. If you can’t, what about giving each item in your game a unique identifier, and saving that. Doesn’t have to be name.

Otherwise to literally save its path use Instance:GetFullName

1 Like

I can’t just save the names of it because it has custom properties that I had built-in and Instance:GetFullName returns a string?

Yes, it returns a string which is the path to it.

print(workspace.Baseplate:GetFullName()) --> Workspace.Baseplate

hmmm but I have a weapon in the table by default how do I do this when it is default?