"Attempt to index nil" in DataStores with a stat that definitely exists

I have a saving/loading system in my game that is being rather problematic. Note that this is my second game with a DataStore system, so I’m likely making a rookie mistake.

Here’s the code for saving:

local function savestores(player)
	local itemset = workspace.PlayerData:FindFirstChild(player.Name).Inventory:GetChildren()
	local items = {}
	for i, v in pairs(itemset) do
		table.insert(items, v.Name)
	end
	local saved = {
		cash = workspace.PlayerData:FindFirstChild(player.Name).Cash.Value,
		playerequip = workspace.PlayerData:FindFirstChild(player.Name).Equips.PlayerEquip.Value,
		zombieequip = workspace.PlayerData:FindFirstChild(player.Name).Equips.ZombieEquip.Value,
		inventory = items
	}
	save:SetAsync(player.UserId, saved)
	workspace.PlayerData:FindFirstChild(player.Name):Destroy()
end

This all saves correctly.

Here’s the code for the loading

local success, saved = pcall(function() save:GetAsync(player.UserId) end)
	if not success or save:GetAsync(player.UserId) == nil then
		print(save:GetAsync(player.UserId))
		-- insert save creation code, which I'm cutting for clarity's sake
	else
		print(save:GetAsync(player.UserId))
		-- load save
		local folder = Instance.new("Folder")
		folder.Name = player.Name
		folder.Parent = workspace.PlayerData

		local equips = Instance.new("Folder")
		equips.Name = "Equips"
		equips.Parent = folder
		local inventory = Instance.new("Folder")
		inventory.Name = "Inventory"
		inventory.Parent = folder
		local cash = Instance.new("NumberValue")
		cash.Name = "Cash"
		cash.Parent = folder

		pcall(function()
			if saved["inventory"] and saved["inventory"] ~= nil then -- this works perfectly, the inventory loads correctly
				for i, v in pairs(saved["inventory"]) do
					local item = Instance.new("BoolValue")
					item.Name = v.Name
					item.Parent = inventory
				end
			else
				local item1 = Instance.new("BoolValue")
				item1.Name = "Sprint"
				item1.Parent = inventory
				local item2 = Instance.new("BoolValue")
				item2.Name = "Smell"
				item2.Parent = inventory
			end
		end)
		if saved["playerequip"] ~= nil then -- this is the problematic part.
			local playerequip = Instance.new("StringValue")
			playerequip.Name = "PlayerEquip"
			playerequip.Value = saved["playerequip"]
			playerequip.Parent = equips
		else
			local playerequip = Instance.new("StringValue")
			playerequip.Name = "PlayerEquip"
			playerequip.Value = "Sprint"
			playerequip.Parent = equips
		end

		if saved["zombieEquip"] ~= nil then
			local playerequip = Instance.new("StringValue")
			playerequip.Name = "ZombieEquip"
			playerequip.Value = saved["zombieequip"]
			playerequip.Parent = equips
		else
			local playerequip = Instance.new("StringValue")
			playerequip.Name = "ZombieEquip"
			playerequip.Value = "Smell"
			playerequip.Parent = equips
		end
	end

On running the game, the output window spits out a “attempt to index nil error” on the if saved["playerequip"] ~= nil then line. What’s bizarre about this is, earlier in the code, I have the system print out the loaded datastore, and, lo and behold, the correctly saved value named “playerequip” is right there! I am incredibly frustrated. What am I doing wrong?

1 Like

The error occurs when you try to index a nil/unknown value, AKA;

print(nil["Name"]) -- `nil` is indexed, and since `nil` isn't a table, it throws an error

You should always re-read error messages to try and understand what they mean, but I get it if you find them a little cryptic at times.

It looks like you have made a few typos in the pcall function where you write saved, as opposed to earlier in the code where you write save without the d:

Try replacing it with

if save["inventory"] then

(There’s no point having another save["inventory"] ~= nil as nil is one of the two falsey values, along with false, meaning that the check won’t pass if it is either nil or false.)

ALSO ALSO, you can just use save.inventory instead of using save["inventory"].

Actually, this is not a typo. “save” refers to the DataStore save, “saved” refers to the player’s save in the “save”.
Thanks for the advice on the inventory thing though, but this still doesn’t fix the issue,

As the error states, saved must be a nil value. Where in your code do you set saved? Also, you should try and have more descriptive variable names. You can very easily add or forget to add the d, and it can make it more difficult for people to understand your code when you post it to #help-and-feedback:scripting-support.

For example, maybe save should be renamed playerData and saved to playerSaveSlot. It’s a lot clearer, at least for me, to know that playerData must be all the player’s save data, and playerSaveSlot is an individual save file of a session.

OH! I see!
I forgot to clarify: the output is spitting out the index nil for the “playerequip”, not for the “saved”.

The code is wrapped in a pcall, so of course you will not see the error the first time. Then, the part of the code that actually shows the error is not in a pcall. If you remove the pcall, I suspect the error will occur in the first -- this works perfectly, the inventory loads correctly line.

local MyDictionary = {
	a = 2,
	b = " hi" 
}

print("Dictionary:", MyDictionary)

print("Key C of dictionary:", MyDictionary.c) -- this prints `nil`, and does NOT give an error!

print("Key A of dictionary:", MyDoctionry.a) -- this does not print, but instead gives an error!

As you can see, despite key c not being in MyDictionary, it doesn’t give an error and instead prints nil. Then, if I misspell the dictionary as MyDoctionry instead, it gives the error “attempt to index nil with [key]” because MyDoctionry doesn’t exist as a variable and is therefore nil.

Can you point out the line you think saved is being declared in? I do not see line saying local saved = ....

Saved is declared in the pcall at the top (success, saved = --). I renamed save to datasave and saved to playersave and it still gives me the error, so it isn’t a typo. You were right about the inventory pcall() thing, though, it does give an error.

Resolved. The issue was the pcall() from the beginning. I guess I just need to get to know that function better.

You have to actually return the value:

local success, saved = pcall(function()
    return save:GetAsync(player.UserId)
end)

The indentation makes it seem like the code below the pcall is actually inside it.

EDIT:

Glad you figured it out!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.