"tables cannot be cyclic" - DataStore Get function

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

Nothing prints and my studio freezes. Thanks!

1 Like

This has already been answered on the internet.
Search up “tables cannot be cyclic” on google.

I did. The replies don’t really help me though.


image
image
I don’t see how my problem has to do with any of those.

In case you’re lazy:

You’re probably just sending the wrong table when attempting to Update it

1 Like

When changing the name of the datastore, the problem still remains.
My old data should be nil.

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.

1 Like

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,
image
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
2 Likes

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.

2 Likes

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, …

1 Like

I’m pretty sure it is, it says “tables cannot be cyclic, line 73”, which is
playerData[userId] = got
(at the end)

	if typeof(got) == "table" then
		playerData[userId] = got
	else
		got = "corrupted"
	end
	return got

playerData is just an empty table I defined at the top of the script. It should hold everyone’s data.
local playerData = {}

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.

2 Likes

Cannot see the full comment.



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.

1 Like

No way!
I did. ;-; How could I oversee that.
Thank you!!

1 Like