Hi! I’m scripting a datastore and for some reason im getting following error: “tables cannot be cyclic” (catched by the pcall)
function module.Get(userId)
local data
while data == nil do
waitForRequestBudget(Enum.DataStoreRequestType.UpdateAsync)
local success, errormessage = pcall(DataStore.UpdateAsync, DataStore, userId, function(oldValue)
if oldValue == nil then
--he is new
print("He is new!")
local setTo = {data = {},
sessionLock = {t = os.time()}}
data = setTo
return setTo
else
--he isn't new
print("He is not new!")
if oldValue.sessionLock.t then
local isDead = os.time() - oldValue.sessionLock.t > MAX_ELAPSED
if isDead == true then
print("Session is dead!")
oldValue.sessionLock.t = os.time()
data = oldValue
return oldValue
else
print("Session is not dead!")
--else it will just retry cuz data will stay nil
return
end
else
--his sessionLock is nil
oldValue.sessionLock.t = os.time()
data = oldValue
return oldValue
end
end
end)
if errormessage then
warn(errormessage)
end
end
if typeof(data) == "table" then
playerData[userId] = data
else
data = "corrupted"
end
return data
end
The quote below explains why “Nothing prints and my studio freezes” is happening.
You’re doing a loop, while data == nil, in this case if data is still nil then it would cause a StartProcessException, which freezes your studio. And what’s worse is you don’t have a limiter which would make the loop slow down a little bit so that Lua can handle it.
The studio freezing is because the data can’t be set I think, so it will stay nil and the while loop will retry inf times.
I added a customWait(5) to it. Now, it doesn’t freeze
function module.Get(userId)
local data
while data == nil do
waitForRequestBudget(Enum.DataStoreRequestType.UpdateAsync)
customWait(5)
local success, errormessage = pcall(DataStore.UpdateAsync, DataStore, userId, function(oldValue)
if oldValue == nil then
--he is new
print("He is new!")
local setTo = {data = {},
sessionLock = {t = os.time()}}
data = setTo
return setTo
else
--he isn't new
print("He is not new!")
if oldValue.sessionLock.t then
local isDead = os.time() - oldValue.sessionLock.t > MAX_ELAPSED
if isDead == true then
print("Session is dead!")
oldValue.sessionLock.t = os.time()
data = oldValue
return oldValue
else
print("Session is not dead!")
--else it will just retry cuz data will stay nil
return
end
else
--he is fine, his sessionLock became nil
oldValue.sessionLock.t = os.time()
data = oldValue
return oldValue
end
end
end)
if errormessage then
warn(errormessage)
end
end
if typeof(data) == "table" then
playerData[userId] = data
else
data = "corrupted"
end
return data
end
The main problem is the error though, I can remove that wait if I figure that out.
I just noticed that I have 2 datas, the one in the table and the one as variable.
Replaced it. Still the same error.
function module.Get(userId)
local got
while got == nil do
waitForRequestBudget(Enum.DataStoreRequestType.UpdateAsync)
customWait(5)
local success, errormessage = pcall(DataStore.UpdateAsync, DataStore, userId, function(oldValue)
if oldValue == nil then
--he is new
print("He is new!")
local setTo = {data = {},
sessionLock = {t = os.time()}}
got = setTo
return setTo
else
--he isn't new
print("He is not new!")
if oldValue.sessionLock.t then
local isDead = os.time() - oldValue.sessionLock.t > MAX_ELAPSED
if isDead == true then
print("Session is dead!")
oldValue.sessionLock.t = os.time()
got = oldValue
return oldValue
else
print("Session is not dead!")
--else it will just retry cuz data will stay nil
return
end
else
--he is fine, his sessionLock became nil
oldValue.sessionLock.t = os.time()
got = oldValue
return oldValue
end
end
end)
if errormessage then
warn(errormessage)
end
end
if typeof(got) == "table" then
playerData[userId] = got
else
got = "corrupted"
end
return got
end
Solution to your main problem, you have a infinite recursion.
I was looking at other posts, and it concludes to the above.
Also,
Look back at the image, it explains "A brief test case that demonstrates this error is t = {}t[1] = t game.HttpService:JSONEncode(t)".
In your code, you are doing some crazy stuff that I can barely understand.
Why not just do this.
function module.Get(userId)
local self = module
local data
DataStore.UpdateAsync(UserId,function(Ov)
if not Ov then return {dat={},sessionLock={time=os.time()}} end
if Ov.sessionLock.time then
local isDead = (os.time() - Ov.sessionLock.time) > MAX_ELAPSED
if isDead then
Ov.sessionLock.Time = os.time()
data = Ov
return Ov
else
-- Nothing.
end
end
end)
return data
end
Are you sure this is the right (part of the right) script? Cyclic tables are tables that refer to themselves within, but unless you have a custom implementation of os.time() I can’t imagine how you’d be getting that error.
Because your example is not retrying, not caring about it being corrupted, not setting the data to the data template when he is new, not waiting (waitForRequestBudget), no pcall, …
Oh, that means your UpdateAsync’s transform function is probably fine. Is there any chance you could be calling this function with :Get rather than .Get, and that playerData is both part of module and contains module at some point in time? If not, there’d have to be some kind of weird metatable stuff going ok, but if playerData is just a table it couldn’t be that.
I didn’t put the whole script in because I typed it on the website, I am just saying you should’ve tried it in a simpler way, while still using all the features you were using in your script.