Trying to retrieve a table from DataStore but it says "Unable to cast value to Object"

local DataStoreService = game:GetService("DataStoreService")

local DataStorage = DataStoreService:GetDataStore("Bananas", "Melons", "Slots")

game.Players.PlayerAdded:Connect(function(player) 
	
	player:WaitForChild("PlayerGui"):WaitForChild("Gui"):WaitForChild("Inventory")
	
	local PlayerKey = "Id_"..player.UserId
	
	local success, data = pcall(function()
		return DataStorage:GetAsync(PlayerKey)
	end)
	
	
	local Leaderstats = Instance.new("Folder")
	Leaderstats.Name = "leaderstats"
	Leaderstats.Parent = player


	local Bananas = Instance.new("NumberValue")
	Bananas.Parent = Leaderstats
	Bananas.Name = "Bananas"
	
	local Melons = Instance.new("NumberValue")
	Melons.Parent = Leaderstats
	Melons.Name = "Melons"
	
	local InventorySlots = data.Slots or 0
	
	print(InventorySlots)

	if success then
		Bananas.Value = data.Bananas or 0
		print("Successfully loaded Bananas : "..data.Bananas.." for "..player.Name)
		Melons.Value = data.Melons or 0
		print("Successfully loaded Melons : "..data.Melons.." for "..player.Name)	
		for _,Slot in pairs(player.PlayerGui.Gui.Inventory.Frame.InventorySlots.ScrollingFrame:GetChildren()) do
			if Slot:IsA("ImageButton") then
				if Slot.SlotValue.Value ~= "0" then
					Slot.SlotValue = data.InventorySlots
					for i, str in ipairs(data.InventorySlots) do
						if type(str) == "string" and string.match(str, Slot.Name.."Slot%d%d%d%d?") then
							local pos = str:find("t")
							Slot.SlotValue = str:sub(pos + 1, pos + 1)
						end
					end
				end
			end
		end
	end

	if not success then
		print("Could not load save data for "..player.Name)
	end

end)

game.Players.PlayerRemoving:Connect(function(player: Player) 
	local PlayerKey = "Id_"..player.UserId
	local success, result = pcall(function()	
		
		local InventorySlots
		
		if script.Parent.InventoryPosting.Players:FindFirstChild(player.Name):FindFirstChildOfClass("StringValue") then
			local RawInventoryData = script.Parent.InventoryPosting.Players:FindFirstChild(player.Name):FindFirstChildOfClass("StringValue")
			InventorySlots = {}
			for _,SlotDataCell in pairs(RawInventoryData:GetChildren()) do
				table.insert(InventorySlots, SlotDataCell.Name)
			end
			print("Recieved the following inventory data to save : ", InventorySlots)
		end
	
		local PlayerData = {
			Bananas = player.leaderstats.Bananas.Value,
			Melons = player.leaderstats.Melons.Value,
			Slots = InventorySlots,
		}
		
		DataStorage:SetAsync(PlayerKey, PlayerData)
	end)
	if not success then
		warn(result) print("Data did not save correctly on player leave")
	end
end)

game:BindToClose(function()
	for _, player in pairs(game.Players:GetPlayers()) do
		local PlayerKey = "Id_"..player.UserId
		local success, result = pcall(function()
			
			local InventorySlots
			
			if script.Parent.InventoryPosting.Players:FindFirstChild(player.Name):FindFirstChildOfClass("StringValue") then
			    local RawInventoryData = script.Parent.InventoryPosting.Players:FindFirstChild(player.Name):FindFirstChildOfClass("StringValue")
			    InventorySlots = {}
			    for _,SlotDataCell in pairs(RawInventoryData:GetChildren()) do
				    table.insert(InventorySlots, SlotDataCell.Name)
			    end
			    print("Recieved the following inventory data to save : ", InventorySlots)
			end
			
			local PlayerData = {
				Bananas = player.leaderstats.Bananas.Value,
				Melons = player.leaderstats.Melons.Value,
				Slots = InventorySlots,
			}
			
			DataStorage:SetAsync(PlayerKey, PlayerData)
		end)
		if not success then
			warn(result) print("Data did not save correctly on server shut down")
		end
	end
end)

I am attempting to create a data store script that allows the saving of inventory, but it keeps putting out the error in the title when i try to add the “Slots” string to GetDataStore. It works fine if i do not have “Slots” put in GetDataStore, and it loads the Bananas and Melons correctly. Is there any way to prevent this. The loop code that sets the inventory slots to the saved values is not done, so ignore that.

I believe this happens because you are passing multiple arguments inside DataStoreService:GetDataStore("Bananas", "Melons", "Slots").

DataStoreService:GetDataStore() only takes one argument, that being the key you are trying to load.

Instead of doing this, you can do one of the following:

  1. Have three separate DataStores each with their own values.
  2. Have a DataStore like “MainPlayerData”

In this case, I’ll be using the second since it is more optimal. You can also use different keys:

local DataStoreService = game:GetService("DataStoreService")

local DataStorage = DataStoreService:GetDataStore("MainPlayerData")

game.Players.PlayerAdded:Connect(function(player) 
	
	player:WaitForChild("PlayerGui"):WaitForChild("Gui"):WaitForChild("Inventory")
	
	local PlayerKey = "Id_"..player.UserId
	
	local success, data = pcall(function()
		return DataStorage:GetAsync(PlayerKey)
	end)
	
	
	local Leaderstats = Instance.new("Folder")
	Leaderstats.Name = "leaderstats"
	Leaderstats.Parent = player


	local Bananas = Instance.new("NumberValue")
	Bananas.Parent = Leaderstats
	Bananas.Name = "Bananas"
	
	local Melons = Instance.new("NumberValue")
	Melons.Parent = Leaderstats
	Melons.Name = "Melons"
	
	local InventorySlots = data.Slots or 0
	
	print(InventorySlots)

	if success then
		Bananas.Value = data.Bananas or 0
		print("Successfully loaded Bananas : "..data.Bananas.." for "..player.Name)
		Melons.Value = data.Melons or 0
		print("Successfully loaded Melons : "..data.Melons.." for "..player.Name)	
		for _,Slot in pairs(player.PlayerGui.Gui.Inventory.Frame.InventorySlots.ScrollingFrame:GetChildren()) do
			if Slot:IsA("ImageButton") then
				if Slot.SlotValue.Value ~= "0" then
					Slot.SlotValue = data.InventorySlots
					for i, str in ipairs(data.InventorySlots) do
						if type(str) == "string" and string.match(str, Slot.Name.."Slot%d%d%d%d?") then
							local pos = str:find("t")
							Slot.SlotValue = str:sub(pos + 1, pos + 1)
						end
					end
				end
			end
		end
	end

	if not success then
		print("Could not load save data for "..player.Name)
	end

end)

game.Players.PlayerRemoving:Connect(function(player: Player) 
	local PlayerKey = "Id_"..player.UserId
	local success, result = pcall(function()	
		
		local InventorySlots
		
		if script.Parent.InventoryPosting.Players:FindFirstChild(player.Name):FindFirstChildOfClass("StringValue") then
			local RawInventoryData = script.Parent.InventoryPosting.Players:FindFirstChild(player.Name):FindFirstChildOfClass("StringValue")
			InventorySlots = {}
			for _,SlotDataCell in pairs(RawInventoryData:GetChildren()) do
				table.insert(InventorySlots, SlotDataCell.Name)
			end
			print("Recieved the following inventory data to save : ", InventorySlots)
		end
	
		local PlayerData = {
			Bananas = player.leaderstats.Bananas.Value,
			Melons = player.leaderstats.Melons.Value,
			Slots = InventorySlots,
		}
		
		DataStorage:SetAsync(PlayerKey, PlayerData)
	end)
	if not success then
		warn(result) print("Data did not save correctly on player leave")
	end
end)

game:BindToClose(function()
	for _, player in pairs(game.Players:GetPlayers()) do
		local PlayerKey = "Id_"..player.UserId
		local success, result = pcall(function()
			
			local InventorySlots
			
			if script.Parent.InventoryPosting.Players:FindFirstChild(player.Name):FindFirstChildOfClass("StringValue") then
			    local RawInventoryData = script.Parent.InventoryPosting.Players:FindFirstChild(player.Name):FindFirstChildOfClass("StringValue")
			    InventorySlots = {}
			    for _,SlotDataCell in pairs(RawInventoryData:GetChildren()) do
				    table.insert(InventorySlots, SlotDataCell.Name)
			    end
			    print("Recieved the following inventory data to save : ", InventorySlots)
			end
			
			local PlayerData = {
				Bananas = player.leaderstats.Bananas.Value,
				Melons = player.leaderstats.Melons.Value,
				Slots = InventorySlots,
			}
			
			DataStorage:SetAsync(PlayerKey, PlayerData)
		end)
		if not success then
			warn(result) print("Data did not save correctly on server shut down")
		end
	end
end)

You can also use multiple keys for your DataStore (like “Id_123_Melons”, “Id_123_Bananas”, “Id_123_Inventory”.

Try the code I gave you and let me know if it works.

What you said was kinda vague, do you know what GetDataStore actually does? I thought it was retrieving the values saved by SetAsync. Those would be the ones in PlayerData, so you would have to call them as what they are called (“Bananas” or “Melons”, ect…) Or does it just create a “Datastore” instance that has the stuff in it. In that case, how would I set it up correctly.

Also, I tried your code, it simply makes everything that was saved nil (not existing) but if i do the thing with multiple strings i can load the data, just without the slots like i mentioned.

Not actually. :GetDataStore() can only take one argument, with an optional scope. It is basically creating a new DataStore.

Imagine this scenario:
You want to create a halloween event for your game inside the main data. Instead of creating a new DataStore name, you can give it a scope.

local DataStoreService = game:GetService("DataStoreService")

local mainData = DataStoreService:GetDataStore("PlayerData")
local halloweenData = DataStoreService:GetDataStore("PlayerData", "Halloween2026") -- new datastore inside PlayerData, if that makes sense

-- HalloweenData: { Candy = 30, HalloweenEggsOpened = 3 }
-- PlayerData: { Coins = 200, Gems = 50, XP = 100 }

-- You access keys the same as you would with mainData
print(halloweenData:GetAsync("Id_123").Candy or "Candy has not been tracked!") -- 30
print(mainData:GetAsync("Id_123").Coins or "Coins have not been tracked!") -- 200

print(mainData:GetAsync("Id_123").EggsOpened or "Player has not opened any eggs!") -- Player has not opened any eggs!

Scopes are mostly for creating test values or in-game events attribuited to the main data.
This is the equivalent of:

local DataStoreService = game:GetService("DataStoreService")

local mainData = DataStoreService:GetDataStore("PlayerData")
local halloweenData = DataStoreService:GetDataStore("Halloween2026PlayerData")

-- HalloweenData: { Candy = 30, HalloweenEggsOpened = 3 }
-- PlayerData: { Coins = 200, Gems = 50, XP = 100 }

print(halloweenData:GetAsync("Id_123").Candy or "Candy has not been tracked!") -- 30
print(mainData:GetAsync("Id_123").Coins or "Coins have not been tracked!") -- 200

print(mainData:GetAsync("Id_123").EggsOpened or "Player has not opened any eggs!") -- Player has not opened any eggs!

You can instead save the values in a table inside PlayerData, in the following example:

local DataStoreService = game:GetService("DataStoreService")

local mainData = DataStoreService:GetDataStore("PlayerData")

local function saveData(plr: Player): boolean, string?
    local success, result = pcall(function()
        mainData:SetAsync("Id_"..plr.UserId, {
            Coins = 100,
            Gems = 50,
            XP = 75
        })
    end)

    return success, result
end

local function getData(key: string, value: string): any
    return mainData:GetAsync(key)[value] or nil
end

print(tostring(getData("Id_123", "Coins"))) -- If Id_123 has been assigned, it will output to 100. Otherwise, nil.

Side note: If you’re saving things like tables / inventories it is recommended to use JSONEncode

Im not gonna mark a solution cause idk what happened. I changed things and then changed them back from my original script and it works now. I could not begin to tell you what happened, but it works. It prints a table of all of the pets that used to be in my inventory.

well that’s good, glad you got it working :slightly_smiling_face:

:GetDataStore() accepts 3 arguments. The DataStore name, the scope of the DataStore and a DataStoreOptions Instance. But in your case when you add "Slots" that’s a string and not an Instance which is why the error happens. For saving player data you usually only need the name of the DataStore in the :GetDataStore()

DataStoreService:GetDataStore()