Data Stores attempt to index a nil value with a leaderstat that DOES exist

Hello, so I am creating a racing game where your character is a ball and when you reach the end of the map you get your coins and stuff. But that’s not the issue. My data store scripts are returning nil for my “Coins” leaderstat value and I don’t know why. I haven’t worked with Data Stores much so I know there is something I’m doing wrong but don’t know what. The function that is returning nil is the :ChangeStat() function I’ve created in a module:

function PlayerStatManager:ChangeStat(player, statName, changeValue)
	sessionData[player][statName] = sessionData[player][statName] + changeValue
	updateboard(player)
end

(PlayerStatManager is a reference to the module)
And the end point of the maps is what triggers this function through a touched event but it keeps erroring saying “Attempt to index nil with ‘Coins’”. This is my script that uses the :ChangeStat() function:

		local leaderstats = player:FindFirstChild("leaderstats")
		if leaderstats then
			local coins = leaderstats:FindFirstChild("Coins")

			if coins and (coins:IsA("IntValue") or coins:IsA("NumberValue")) then
	
				PlayerStatManager:ChangeStat(player, "Coins", 10)
		
			else
				warn("Finish script: 'Coins' stat not found or not a valid number value for player " .. player.Name)
			end
			hasFinishedValueHolder.Value = true
		else
			warn("Finish script: 'leaderstats' not found for player " .. player.Name)
		end
	end

I tried testing it on the Roblox client, but still errored out. It probably is a stupid mistake but for now I can’t see it as I’m inexperienced with Data Stores

  • Why are you defining a method if you never use self?

You better to learn about datastore implementation from ProfileStore - Save your player data easy (DataStore Module) and Data stores | Documentation - Roblox Creator Hub
ProfileStore is a pretty well made module and you could either study off from it or implement it into your game or do both (recomended)

1 Like

It’s not a problem with datastores, it’s problem with tables.
The problem you’re having is this:

Table = {}
Table["Player"]["Currency"] = 10

if you’d run this code in studio it would give you the same error because if Table doesn’t contain the PlayerData it would not create 2 tables at once. This would work:

Table = {}
Table["Player"] = {}
Table["Player"]["CoinsAmount"] = 10

You need to check if sessionData[player] exists, if not then create the table sessionData[player] = {} after checking that you can safely get sessionData[player][statName] and change it

I do check that, It’s in this function:

local function setupPlayerData(player)
	local success, data = getPlayerData(player)
	if not success then
		--Could not access the DataStore, set session data for player to false
		sessionData[player] = false
	else
		if not data then
			--DataStores are working, but no data for this player
			sessionData[player] = {Coins = 0}
			savePlayerData(player)
		else
			--DataStore is working and data was found for this player
			sessionData[player] = data
		end
		
	end
	updateboard(player)
end

Plus the updateboard function if you need it:

local function updateboard(player)
	for i,e in pairs(sessionData[player]) do
		print(i,e)
		player.leaderstats[i].Value = e
	end
end

Thank you for this but I’m trying to keep the module I already have, I will look into this for future projects though

It seems normal, could it be in the way that you’re saving the data?
Try printing data if it prints {Coins = 2}
if it prints only the amount then just change last line to sessionData[player] = {Coins = data}

1 Like

It never gets to that point, I tried checking if sessionData[player] exists and it is returning false

if not sessionData[player] then
			warn("Player data has not been loaded!")
			return
		end

It is printing “Player data has not been loaded!”. The player exists but not their data, this makes sense that the updateboard function is not responding. I’m going to try and wait for leaderstats to show up and see if that works

EDIT: The leaderstats are found and sessionData[player] still returns nil. I tried creating a seperate table but same thing. Any ideas? I can post the whole module if that will be helpful

Here is the whole module:

local PlayerStatManager = {}

local DSS = game:GetService("DataStoreService")
local playerData = DSS:GetDataStore("PlayerData")
local AUTOSAVE_INTERVAL = 60
local DATASTORE_RETRIES = 3
local sessionData = {}
--Function to Update the LeaderBoard
local function updateboard(player)
	--local realsessiondata = sessionData[player]
	sessionData[player] = {}
	for i,e in pairs(sessionData[player]) do
		print(i,e)
			player:WaitForChild("leaderstats")[i].Value = e
	end
end

function PlayerStatManager:ChangeStat(player, statName, changeValue)
	if player and player:WaitForChild("leaderstats") and player.leaderstats:WaitForChild(statName) then
		if not player then
			warn("Player is nil!")
			return
		end
		if not sessionData then
			warn("Table doesn't exist")
			return
		end
		if not sessionData[player] then
			warn("Player data has not been loaded!")
			return
		end
		sessionData[player][statName] = sessionData[player][statName] + changeValue
		updateboard(player)
	end
end

local function dataStoreRetry(dataStoreFunction)
	local tries = 0
	local success = true
	local data = nil

	repeat
		tries = tries + 1
		print(tries)
		success = pcall(function() data = dataStoreFunction() end)
		if not success then
			wait(1)
		end

	until tries == DATASTORE_RETRIES or success

	if not success then
		error("Could not access DataStore! Data might not save!")
	end
	return success, data
end

local function getPlayerData(player)
	return dataStoreRetry(function()
		return playerData:GetAsync(player.UserId)
	end)
end

local function savePlayerData(player)
	if sessionData[player] then
		return dataStoreRetry(function()
			return playerData:SetAsync(player.UserId, sessionData[player])
		end)
	end
end

local function setupPlayerData(player)
	local success, data = getPlayerData(player)
	print(data)
	if not success then
		--Could not access the DataStore, set session data for player to false
		sessionData[player] = false
	else
		if not data then
			--DataStores are working, but no data for this player
			sessionData[player] = {Coins = 0}
			savePlayerData(player)
		else
			--DataStore is working and data was found for this player
			sessionData[player] = {Coins = data}
		end

	end
	updateboard(player)
end

local function autosave()
	while wait(AUTOSAVE_INTERVAL) do
		for player, data in pairs(sessionData) do
			savePlayerData(player)
		end
	end
end
--Bind setupPlayerData to PlayerAdded to call it when player joins
game.Players.PlayerAdded:Connect(setupPlayerData)
--Call savePlayerData on PlayerRemoving to save player data when they leave
--Also delete the player from the sessionData, as the player isn't in game anymore
game.Players.PlayerRemoving:Connect(function(player)
	savePlayerData(player)
	sessionData[player] = nil
end)
--Start running autosave function in the background
spawn(autosave)
--Return the PlayerStatManager table to external scripts so they can access it
return PlayerStatManager