"tables cannot be cyclic" error. Data not saving

Heya, I have just now encountered this error that (I assume) prevents data from saving as since it started showing up data stopped saving.

I have looked at other posts with this error but I did not understand a single thing.

Code:

FUNCTION 1: Get default data.

function module:GetDefaultData()
	return {
		["Costumes"] = {
			["Dan"] = "false",
			
			["Alex"] = "false",
			
			["Emma"] = "false",
			
			["Princess"] = "false",
			
			["Betty"] = "false",
			
			["Matilda"] = "false",
			
			["Demon"] = "false",
			
			["Fairy"] = "false",
			
			["Angel"] = "false",
			
			["Nephalem"] = "false",
			
			["Emotimask Derpy"] = "false",
			
			["Emotimask Cute"] = "false",
			
			["Emotimask Smiley"] = "false",
			
			["Candy Corn"] = "false",
		},
		
		["Currencies"] = {
			["Candy"] = 0
		},
		
		["EverPlayed"] = "false",
		
		["Current Costume"] = "",
		
		["Current BodyType"] = "",
		
		["Quests"] = {
			
			["Paranormal Hunter"] = {
				["Status"] = nil,
				["Progress"] = nil,
				["Cooldown"] = 0,
			},
			
			["Letter"] = {
				["Status"] = nil,
				["Progress"] = nil,
				["Cooldown"] = 0,
			},
		},
	}
end

FUNCTION 2: Check if data has changed since last time (don’t think it’s related but could it started happening when I implemented this into the script).

function module.Check(Data)
	
	local DefaultData = module:GetDefaultData()
	
	local function LoopThroughTable(Table,CompareTable)
		
		for Key,Value in pairs (Table) do
			
			if Data[Key] == nil then
				Data[Key] = Value
			end
			
			
			if type(Value) == "table" then
				
				for Key1,Value in pairs (Table) do
					
					if Data[Key][Key1] == nil then
						Data[Key][Key1] = Value
					end
					
					if type(Value) == "table" then
						for Key2,Value in pairs (Table) do
							
							if Data[Key][Key1][Key2] == nil then
								Data[Key][Key1][Key2] = Value
							end
							
						end
					end
				end
			end
		end
		
	end
	
	LoopThroughTable(DefaultData,Data)
	
end

FUNCTION 3: Saving the data

function module.SaveData(client)
	if module.sessionData[client.UserId] then
		local success,errormessage
		local tries = 0
		repeat
			success,errormessage = pcall(function()
				DataStore:UpdateAsync(client.UserId, function()
					return module.sessionData[client.UserId]
				end)
			end)
			if errormessage ~= nil then
				wait(6)
				tries += 1
			end
		until success or tries >= 2
		if tries >= 2 then
			print(errormessage," if you see this: take a screenshot and report to the discord server")
		end
		
		module.sessionData[client.UserId] = nil
	end
end

Any help is appreciated!

1 Like

Did it get any errors though??

“tables cannot be cyclic” is the error.

You’re saving the Data even if it fails right?, And does it keep trying until it saves?

I repeat the process of saving up to 2 times if it fails.

Is SessionData A table?, And what line does it error on?

Yes, sessionData is a table, it’s where all the player’s Data (tables) are stored in. It doesn’t say which line it errors on. This is the whole error in output:
Screenshot_2332

The problem is you’re doing setting sessionData as a table then you’re doing SessionData[whatever number or something here] = whatever, Here is a example I found:

   local SessionData = {}
   local TransferData
   local MainData = Data

   -- Here is the example of where you would go wrong:


    SessionData[MainData] = TransferData

Any table where a value in its hierachy points is cyclic.

1 Like

I didn’t really understand this part:

Could you reword it if possible?

Also… If that’s what’s happening how would I fix it?

Okay so what I mean’t was, You’re equalling a table to its same hierachy points, Meaning you’re equalling it to its same value/points (Im not 100 percent sure but from my knowledge this is what I know)

Try using the function unpack In the SessionDataTable

1 Like

Still gives me the error. Didn’t really know where to put the unpack function and I put it at the start of SaveData function:

function module.SaveData(client)
	
	unpack(module.sessionData)

unpack({module.sessionData}]).

1 Like

Since you’re wrapping module.sessionData in a table before unpacking it, that just gives you module.sessionData again.

5 Likes

Still gave me the error (I tried unpack({module.sessionData}) and unpack({module[“sessionData”]}) since unpack({module.sessionData}]) didn’t work).

Edit note: If I don’t respond I’m asleep, it’s 2 AM and I don’t want to mess up my sleep schedule too much.

This should be some help

–
But a summary of that is basically:
Somewhere in your data table, one value refers to the table itself, like so:

local data = {}
data.Coins = 100
data.Kills = data; -- This is will cause the same error if you were to save this table

The topic was solved because the person unpacked the data table, then put that in another table, like:

save({unpack(data)})

(idk how that really fixes it tbh but ye, edit: also i know it was said before maybe i didnt really read that much but as i reread i see some other people already suggested so maybe scratch that but check out the forum post)

That error occurs in your "FUNCTION 2’'. more precisely when you do Data[Key] = Value, Data[Key][Key1] = Value or Data[Key][Key1][Key2] = Value. because at some point Value is a subtable that was previously saved in “Data” and you are trying to save that subtable in itself. That can be easily solved by making this changes

local function LoopThroughTable(Table,CompareTable)
	for Key,Value in pairs (Table) do

		if Data[Key] == nil then
			Data[Key] = Value
		end

		if type(Value) == "table" then
			for Key1,Value1 in pairs (Value) do
				if Data[Key][Key1] == nil then
					Data[Key][Key1] = Value1
				end
				if type(Value1) == "table" then
					for Key2,Value2 in pairs (Value1) do
						if Data[Key][Key1][Key2] == nil then
							Data[Key][Key1][Key2] = Value2
						end
					end
				end
			end
		end
	end
end

But in this case the method you are using (to fill in your players’ data with default values) is much more complicated than what you implemented (you are missing a lot of checks, that is, ifs) and can fail in many ways.

The easiest way to solve this is to use Recursivity. Unfortunately this is an advanced topic, and not easy to explain, but it is quite effective and much more general. I rewrote your “FUNCTION 2 and 3”:

function module.Check(Data)
	
	local DefaultData = module:GetDefaultData()
	
	local function fillTable(Table, CompareTable)
		for Key, Value in pairs(Table) do
			if type(Value) == "table" then
				if type(CompareTable[Key]) ~= "table" then
					CompareTable[Key] = {}
				end
				fillTable(Value, CompareTable[Key])
			else
				if CompareTable[Key] == nil then
					CompareTable[Key] = Value
				end
			end
		end
	end
	
	fillTable(DefaultData, Data)
end

function module.SaveData(client)
	if module.sessionData[client.UserId] then
		local success, errormessage
		local tries = 0	
		repeat
			tries = tries + 1
			success, errormessage = pcall(function()
				DataStore:SetAsync(client.UserId, module.sessionData[client.UserId])
			end)
			if not success then
				wait(6)
			end
		until tries == 2 or success
		if not success then
			print(errormessage," if you see this: take a screenshot and report to the discord server")
		else	
			module.sessionData[client.UserId] = nil
		end
	end
end

Let me give you some recommendations

  • If you are not familiar with Recursivity, you may not be comfortable with that code. But solving that in the traditional way is much more difficult and you could easily make a mistake.
  • I modified “FUNCTION 3” because it seemed to me that the logic had some flaws. In this tutorial is the correct way to use Datastore
  • I know that the above people have good intentions in suggesting to use unpack, but in this case it will not solve anything
2 Likes

Thank you for the help! I’ll look more into Recursivity so this doesn’t happen again :)!