DataStore | Problems With Loading and Saving

I’ve recently got into DataStores, so it’s basically impossible to trip on the front steps.

Keep in mind that I do know a bit about DataStores so technical language is understandable, but, explanations are helpful, too.


Loading Problem:

The problem is with loading String Values, they will cause errors:

local DataStore = game:GetService("DataStoreService")
local StatisticsDataStore = DataStore:GetDataStore("Statistics")

game.Players.PLayerAdded:Connect(function(player)
    local Stats = Instance.new("Folder")
    Stats.Name = "Stats"
    Stats.Parent = player

    local StringValue = Instance.new("StringValue")
    StringValue.Value = "IDontLikeToWorkAtAll"
    StringValue.Parent = Stats

    local StatisticsKey = player.userId

    local StatLoad = StatisticsDataStore:GetAsync(StatisticsKey)
	
    if StatLoad then
        for i, v in pairs(Stats:GetChildren()) do
            v.Value = StatLoad[i] -- errors here
        end 
    else
        local StatValues = {Stats:GetChildren().Value}
        StatisticsDataStore:UpdateAsync(StatLoad, StatValues)
    end

end)

Here’s the error:

22:13:47.855 - ServerScriptService.Leaderstats:19: bad argument #3 to ‘Value’ (string expected, got nil)

Is there any way to fix this error?


Saving Problem:

game.Players.PlayerRemoving:Connect(function(player)
	local Stats = player:WaitForChild("Stats")
	
	local StatValues = {Stats:GetChildren().Value}
	local StatisticsKey = player.userId
	
	local success, errormessage = pcall(function()
		StatisticsDataStore:UpdateAsync(StatisticsKey, StatValues)
	end)
	
	if success then
		print("success")
	elseif errormessage then
		warn(errormessage)
	end
end)

Instead of a success, it warns:

22:28:31.744 - Unable to cast value to function


Thank you for reading, reply to any questions you have

All help is appreciated!

Firstly, UpdateAsync takes a function as its’ second argument not a value. you return the value you want to save when using UpdateAsync, for example:

Datastore:UpdateAsync(Key, function(PreviousValue)
     return PreviousValue + 5
end)

Secondly the GetChildren() method returns a table of objects with numerical indices (array), meaning when you reference .Value it will return nil, which is what i presumably think you don’t want


And finally likely this:

StatisticsDataStore:UpdateAsync(StatLoad, StatValues)

is throwing an error because StatLoad is nil, which it can’t be when trying to use it as a key to save something to

3 Likes

I think a much better way to do this is putting this in the player removing function instead of your original for loop.

local Table = {}

local children = stats:GetChildren()

for i, v in pairs(children) do
Table[v.Name] = v.Value
end

Then set the sync with that dictionary as the value.

Now in the player added function,

for i, v in pairs(stats:GetChildren() ) do
v.Value = statLoad[v.Name]
end

Instead of the way your doing it right now.

1 Like

@Jaycbee05 and @C0lvy123


@C0lvy123 I used:

local Table = {}

local children = stats:GetChildren()

for i, v in pairs(children) do
    Table[v.Name] = v.Value
end

but when I print
local Table = {}

local children = stats:GetChildren()

for i, v in pairs(children) do
    Table[v.Name] = v.Value
    print(#Table) -- returns 0
end

it returns 0

So I changed it a bit:

for i, v in pairs(Stats:GetChildren()) do
    Table[i] = v.Value
    print(#Table) -- prints 1, 2, 3, 4...
end

But I don’t know if it’s going to work or not(as in saving).


@Jaycbee05

This part worked:

Datastore:UpdateAsync(Key, function(PreviousValue)
     return PreviousValue + 5
end)

It removed the error!

But I don’t understand this part:

What do you mean by the StatLoad is nil?
In the code I wrote:

local StatisticsKey = player.userId

local StatLoad = StatisticsDataStore:GetAsync(StatisticsKey)

StatLoad is defined, but I don’t know if it will return nil, how would I fix this?


I used your solutions and it fixed the erroring, but, I still have this error:
09:57:01.678 - ServerScriptService.Leaderstats:120: bad argument #3 to ‘Value’ (string expected, got nil)

Here’s the chunk of the script that errors

local StatsTable = {}

for i, v in pairs(Stats:GetChildren()) do
	StatsTable[v.Name] = v.Value
end

local StatisticsKey = player.userId

local StatLoad

local success, errormessage = pcall(function()
	StatLoad = StatisticsDataStore:GetAsync(StatisticsKey)
end)

if success then
	if StatLoad then
		for i, v in pairs(Stats:GetChildren()) do
			v.Value = StatLoad[i] -- Errors when iterating through the first string value in the Stats folder
		end
	end
else
	warn(errormessage, "attempting to reload data")
end

Thank you!

It’s an error, because 1 isn’t a valid key of the dictionary. if you do

v.Value = StatLoad[v.Name]

Like I suggested, it should work. The reason it printed 0, was because you didn’t set the sync yet. The sync is set when the player leaves, so change it back to what I told you, PlayTest, leave, and then rejoin. Then check if it works.

It still errors:

18:16:25.477 - ServerScriptService.Leaderstats:118: bad argument #3 to ‘Value’ (string expected, got nil)

what I’m trying to say is that when it comes across a string value in the leaderstats, it errors.

For example:

if I had leaderstats with children like this:

game > Players > LocalPLayer > Stats > Coins(Int)
                                       Stuff(Int)
                                       Bills(Int)
                                       Name(String)

and I were to iterate:

for i, v in pairs(Stats:GetChildren()) do
    print(v.Name) -- Prints: Coins, Stuff, Bills, Name
    v.Value = StatLoad[v.Name]  -- Error: no, no, no yes
end

If you don’t get it feel free to ask, but thank you for staying with me.

1 Like

Originally i was saying it probably was erroring because StatLoad is nil which is what is returned if there is nothing saved under a key when using GetAsync, you were assuming that StatLoad is not nil before trying to use it as a key for UpdateAsync

local StatLoad = StatisticsDataStore:GetAsync(StatisticsKey) --- nil, nothing is saved under the StatisticsKey
...
    else
        local StatValues = {Stats:GetChildren().Value}
        StatisticsDataStore:UpdateAsync(StatLoad, StatValues)
    end

But the reason this:

v.Value = StatLoad[v.Name] 

could be erroring is because StatLoad is not a table/Dictionary. So before you use it as such check if it is nil and if so set it to a table or key whichever you are using it for: (For Example)

if StatLoad == nil then
  StatLoad = {}
end
1 Like

I am getting more confused as we go on(unfortunately).

Instead of pinpointing one error at a time, I will point out every single error this time, and explain it in detail:

game.PLayers.PlayerAdded:Connect(function(player)

    --[ Leaderstats

        -- Just assume there are Int Values and String Values parented to a folder called Stats

    --]]

	--[ DataStore ]--
	
		--[ Stats
		
	local StatsTable = {}
	
	for i, v in pairs(Stats:GetChildren()) do
		StatsTable[v.Name] = v.Value
	end
	
	local StatisticsKey = player.userId
	
	local StatLoad
	
	local success, errormessage = pcall(function()
		StatLoad = StatisticsDataStore:GetAsync(StatisticsKey)
	end)
	
	if success then
		if StatLoad then -- I have no idea why this passes even though it is the first time someone joined the game
			for i, v in pairs(Stats:GetChildren()) do
				v.Value = StatLoad[v.Name] -- Does not error until passing a string value, which would give this error:  [18:58:05.251 - ServerScriptService.Leaderstats:120: bad argument #3 to 'Value' (string expected, got nil)] Meaning that the string value in the leaderstats is causing an error in the code
			end
		else 
	        local StatValues = {Stats:GetChildren().Value}
	        StatisticsDataStore:UpdateAsync(StatLoad, function(StatValues)
				return(StatValues)
			end)
	    end
	else
		warn(errormessage, "attempting to reload data") -- never prints, so the pcall is a success
	end
	
end)

game.Players.PlayerRemoving:Connect(function(player)
	
	local Stats = player:WaitForChild("Stats")
		
	--[ Stats
	
	local StatsTable = {}
	
	for i, v in pairs(Stats:GetChildren()) do
		StatsTable[v.Name] = v.Value
	end

	local StatisticsKey = player.userId

	local success, errormessage = pcall(function()
        print("Test") -- prints
		StatisticsDataStore:UpdateAsync(StatisticsKey, function(StatsTable) -- fires no errors
            print("Test") -- does not print, meaning that the function does not work/the previous 
			return StatsTable
		end)
	end)
    print("Test") -- does not print, meaning that there is something wrong with the previous lines
	if success then
		print("success")
	else
		warn(errormessage, "attempting to save data")
	end
end)

Thank you for staying with me for so long(It’s been like, a day already).

ok, so = StatLoad[v.Name] returns nil. You made an if statement that only runs if statLoad is not nil. (Just making sure I’m correct lol) so, obviously statLoad isn’t nil, because the if statement runs. Maybe StatLoad isn’t a table, in which case you can’t do [] on it, so it would return nil because it makes no sense. (Don’t really know why it would be like that.)

You should do

StatisticsDataStore:SetAsync(StatsTable)

Update A sync Updates a sync that already exists. If you never set a sync, I don’t think updating will create a new one automatically. Idk, maybe if you do that it will straighten some stuff out.

1 Like

But I’ve heard that SetASync can cause errors, but thank you, I will test it out!

1 Like

Yeah, I’ve heard that too. I think a way to use both set and update is to do this:

key = -- the key
value = -- the value
datastore = --the datastore

if datastore:GetAsync(key) == nil then
datastore:SetAsync:(key, value)
else
datastore:UpdateAsync(key, function() return value end)

Never tested, just an idea

1 Like

Here is an article about SetAsync/UpdateAsync. I would not recommend doing what you are doing because oldValue will give nil if there is no data.

@Jaycbee05 @C0lvy123

After some experimenting and some research and many days, I still couldn’t figure out the datastore problem.

But I have one thing for certain: the loading works, but not the saving

Whats wrong with the saving?:

local PlayerKey = "Data-" .. player.UserId

local success, UniqueKey = pcall(function()
	return StatisticsDataStore:GetAsync(PlayerKey)
end)
--[[
  leaderstats code
--]]
local tries = 0	
local success
repeat
	tries = tries + 1
	success = pcall(function()
		StatisticsDataStore:UpdateAsync(UniqueKey, function(Synced) -- Error here
			CurrentData = Synced
			return Synced
		end)
	end)
if not success then wait(1.5) end
until tries == 3 or success

This is the error I get:

17:48:55.811 - Argument 1 missing or nil

I can see why, because the UniqueKey is nil

I also tried SetAsync, but still no luck
Is there a way to make the UniqueKey not nil, or save a value in it?

I tried replacing this line:

local success, UniqueKey = pcall(function()
	return StatisticsDataStore:GetAsync(PlayerKey)
end)

with this

local UniqueKey
local success, err = pcall(function()
	UniqueKey = StatisticsDataStore:GetAsync(PlayerKey)
end)

If you have a solution please help.

Thank you!

I’m guessing you meant for Unique key to be returned in your pcall function:

local success, UniqueKey = pcall(function()
	return StatisticsDataStore:GetAsync(PlayerKey)
end)

Which wouldn’t happen because the second argument/parameter returned by pcall is the error if one occurred which likely didnt occur because UniqueKey is nil. (If your pcall did error ir would give you a string of the error).


To fix this I would define Uniquekey first then set it accordingly inside your pcall function. Also I would check to make sure something is saved to the player before you try use it and or set it to a default key.

1 Like

I read on the Hub and it was written like that:

local success, data = pcall(function()
    return playerData:GetAsync(playerUserId)
end)

How would I make the UniqueKey not nil, then?

Thank you!

Oops, pcall might actually be able to return values returned inside it as it’s at it’s second argument/parameter (can’t remember) i usually just reserve it for the error argument (you can do some research). Whether the pcall is faulty i would still assign a default value, (Which also happens to be your question).

To ensure that UniqueKey is not nil one way is to just simply do:

UniqueKey = UniqueKey or DefualtValue

Before you use as a key for saving something.


Now, i’m not sure what you are exactly trying to save/do but you would replace Default Value with whatever you wanted the key/scope for the update Async function to be if the player has no data or it is their first time playing (if that makes sense)

1 Like

What would the default value be?

Would it be:

local DefaultValue = {what you start out with}

I’ve thought of that, it was also mentioned in the datastore page, but I wasn’t sure if i could save that without a datastore key, but the problem is, there isn’t a datastore key to save with.

If I am wrong please correct me.

Thank you!