Getting an error 'Attempt to index nil with userId'

So, I’m trying to save currencies to a datastore, and when I leave (in this case stop the game), I get an error.
RobloxStudioBeta_OHYi1MH012

I’m pretty sure it’s with the userId not existing cause the player left, though I don’t know how to fix it.

This is the current script:

local datastore = game:GetService("DataStoreService")
local playerDS = datastore:GetDataStore("CurrencyDataStore")
local player = game:WaitForChild("Players").LocalPlayer

game:WaitForChild("Players").PlayerAdded:Connect(function(player)
	local ls = Instance.new("Folder")
	local feathers = Instance.new("NumberValue")
	local gems = Instance.new("NumberValue")
	local sonicwaves = Instance.new("NumberValue")

	ls.Name = "leaderstats"
	feathers.Name = "Feathers"
	gems.Name = "Gems"
	sonicwaves.Name = "SonicWaves"

	ls.Parent = player
	feathers.Parent = ls
	gems.Parent = ls
	sonicwaves.Parent = ls

	local success, errormsg = pcall(function()
		local data = playerDS:GetAsync(player.UserId)
		if data[1] ~= nil then
			feathers.Value = data[1]
		end
		if data[2] ~= nil then
			gems.Value = data[2]
		end
		if data[3] ~= nil then
			sonicwaves.Value = data[3]
		end
	end)
end)

game.Players.PlayerRemoving:Connect(function(Lplayer)
	if player.userId == Lplayer.UserId then
		playerDS:SetAsync(player.UserId, { 
			player.leaderstats.feathers.Value,
			player.leaderstats.gems.Value,
			player.leaderstats.sonicwaves.Value
		})
	end
end)

The error is appearing in the ‘if’ function which checks if the userId is the same as the Id of the left player. I’d really appreciate any help!

Sincerely, Blackstrike.

do game:GetService(“Players”).LocalPlayer instead

1 Like

change userId to UserId
ahhhh yes cool limit

server scripts cannot use LocalPlayer, and by the look of the error, as the script is in ServerScriptService, its a server script.

in that case remove the player variable

How do I make the check work then? Is there any way to implement it?

redid this with sense, u did “userId” not UserId on that line

local playerDS = datastore:GetDataStore("CurrencyDataStore")
local player = game:WaitForChild("Players").LocalPlayer

game:WaitForChild("Players").PlayerAdded:Connect(function(player)
	local ls = Instance.new("Folder")
	local feathers = Instance.new("NumberValue")
	local gems = Instance.new("NumberValue")
	local sonicwaves = Instance.new("NumberValue")

	ls.Name = "leaderstats"
	feathers.Name = "Feathers"
	gems.Name = "Gems"
	sonicwaves.Name = "SonicWaves"

	ls.Parent = player
	feathers.Parent = ls
	gems.Parent = ls
	sonicwaves.Parent = ls

	local success, errormsg = pcall(function()
		local data = playerDS:GetAsync(player.UserId)
		if data[1] ~= nil then
			feathers.Value = data[1]
		end
		if data[2] ~= nil then
			gems.Value = data[2]
		end
		if data[3] ~= nil then
			sonicwaves.Value = data[3]
		end
	end)
end)

game.Players.PlayerRemoving:Connect(function(Lplayer)
	if player.UserId == Lplayer.UserId then
		playerDS:SetAsync(player.UserId, { 
			player.leaderstats.feathers.Value,
			player.leaderstats.gems.Value,
			player.leaderstats.sonicwaves.Value
		})
	end
end)

you get the player in the function alr

image

local part = script.Parent
local debounce = {}

local rS = game:GetService("ReplicatedStorage")
local rEvent = game.ReplicatedStorage.Remote.onFailTeleport

part.Touched:Connect(function(hit)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	if player then
		local checkDb = debounce[player.UserId]
		if checkDb == nil or checkDb == false then
			debounce[player.UserId] = true
			rEvent:Fire(game.Players:GetPlayerFromCharacter(hit.Parent))
			wait(0.2)
			debounce[player.UserId] = false
		end
	end
end)

so just put the event into the event yeah?

local playerDS = datastore:GetDataStore("CurrencyDataStore")

game:WaitForChild("Players").PlayerAdded:Connect(function(player)
	local ls = Instance.new("Folder")
	local feathers = Instance.new("NumberValue")
	local gems = Instance.new("NumberValue")
	local sonicwaves = Instance.new("NumberValue")

	ls.Name = "leaderstats"
	feathers.Name = "Feathers"
	gems.Name = "Gems"
	sonicwaves.Name = "SonicWaves"

	ls.Parent = player
	feathers.Parent = ls
	gems.Parent = ls
	sonicwaves.Parent = ls

	local success, errormsg = pcall(function()
		local data = playerDS:GetAsync(player.UserId)
		if data[1] ~= nil then
			feathers.Value = data[1]
		end
		if data[2] ~= nil then
			gems.Value = data[2]
		end
		if data[3] ~= nil then
			sonicwaves.Value = data[3]
		end
	end)
end)

game.Players.PlayerRemoving:Connect(function(Lplayer)
	if player.UserId == Lplayer.UserId then
		playerDS:SetAsync(player.UserId, { 
			player.leaderstats.feathers.Value,
			player.leaderstats.gems.Value,
			player.leaderstats.sonicwaves.Value
		})
	end
end)```

formatting error, add the local datastore = game:GetService(“DataStoreService”)
aswell

player is an unknown variable cause it’s separated, as the “player” only exists in the PlayerJoined
image

what is the point of this line

Lplayer is the player though -------

To check if the player the datastore wants to save the data is the same at the player who just left, now that I think about it it’s useless.

game.Players.PlayerRemoving:Connect(function(player)
		playerDS:SetAsync(player.UserId, { 
			player.leaderstats.feathers.Value,
			player.leaderstats.gems.Value,
			player.leaderstats.sonicwaves.Value
		})
end)

I’ll try to solution as soon as I get back home. Appreciate your help!

A server script cannot grab a local player, so when you go to save the players data when they’re leaving, it errors, as you are trying to use the local player.

Also, I’d recommend having a bindToClose in the script.

I’ve cleaned up the code a bit, but I would recommend modules such as datastore2 or profileService.

Try this code out.

--Services{
local datastore = game:GetService("DataStoreService")
local playerService = game:GetService("Players")
--}

--Vars{
local playerDS = datastore:GetDataStore("CurrencyDataStore")
--}

--Tables{
local noobie = {
	["Feathers"] = 0;
	["Gems"] = 0;
	["SonicWaves"] = 0
}
--}

local function saveData(player)
	local safeSave = player:GetAttribute("SafeSave")
	
	if safeSave then
		
		local myStats = {
			["Feathers"] = player.leaderstats.Feathers.Value;
			["Gems"] = player.leaderstats.Gems.Value;
			["SonicWaves"] = player.leaderstats.SonicWaves.Value;
		}

		local tries = 0
		local maxTries = 4

		while tries < maxTries do
			local success, errormessage = pcall(function()
				playerDS:SetAsync(player.UserId, myStats)
			end)

			if not success then
				tries += 1
				task.wait(30)
			else
				break
			end
		end
		
	end
end

playerService.PlayerAdded:Connect(function(player)
	local ls = Instance.new("Folder")
	local feathers = Instance.new("NumberValue")
	local gems = Instance.new("NumberValue")
	local sonicwaves = Instance.new("NumberValue")

	ls.Name = "leaderstats"
	feathers.Name = "Feathers"
	gems.Name = "Gems"
	sonicwaves.Name = "SonicWaves"

	ls.Parent = player
	feathers.Parent = ls
	gems.Parent = ls
	sonicwaves.Parent = ls
	
	local data --have the data variable outside the pcall
	
	local success, errormsg = pcall(function()
		data = playerDS:GetAsync(player.UserId)
	end)
	
	if success then
		if not data then
			data = table.clone(noobie)
		end
		
		feathers.Value = data["Feathers"]
		gems.Value = data["Gems"]
		sonicwaves.Value = data["SonicWaves"]
		
		player:SetAttribute("SafeSave", true)
		
	else
		warn(errormsg)
		player:Kick("Data could not be loaded. Please try and rejoin")
	end
end)

playerService.PlayerRemoving:Connect(function(player)
	saveData(player)
end)

game:BindToClose(function()
	for _, v in pairs(playerService:GetPlayers()) do
		saveData(v)
	end
end)

also also, does datastore work in roblox studio? cause when I try to overwrite the value, then quit and load in again it’s still the original value