"tables cannot be cyclic" everytime i encode a table made in a script

so i tried to make a table, but the problem was i cannot get it working. everytime i make a table, the contents were filled with "*** cycle table reference detected ***".

this script says it all, basically all it do prints out the data variable before it gets inserted with table.insert(data.contents, makeChat("hi")) and after it was inserted.

local genai = require(script.Parent.ModuleScript)
local httpService = game:GetService("HttpService")

local chatTemplate = {
	parts = {
	}
}

local httpRequestTemp = {
	contents = {}
}

function makeChat(chat:string, role: "user" | "model" | nil?)
	local chat = chatTemplate

	table.insert(chat.parts, 1, {
		text = chat
	})

	if role then
		chat.role = role
	end
	
	return chat
end

local data = table.clone(httpRequestTemp)
print(data)
table.insert(data.contents, makeChat("hi"))
print(data)

local httpData = httpService:JSONEncode(data)
print(httpData)

output:

when i encode it to a json using httpservice, it says "tables cannot be cyclic".

1 Like

The problem is that you’re inserting a table (chat) into itself. Use a different variable name for chat (and you probably mean to clone it?).

3 Likes

Yup that’s the problem, you can reference your table but you cant put it in itself. Think, you can’t put a bag of holding into another bag of holding.

So store the table somewhere else, and then reference that location via unique key. You may be able to get away with a weak pointer but likely not.

--]]
This is conceptual code so if it works right off the copy past awesome 
otherwise I am trying to demonstrate a process.  You could have a module you 
ref and store it too this way.  And you could then use a short hand ref to the 
UUID

But bare in mind I did this quickly just to demonstrate how to get around 
when you need that kind of functionality.  
--]]

-- EXAMPLE:
local HttpService= game:GetService("HttpService")

--[[
Fresh table each time, hot off the grill and ready for use
]]
local function _createChatTemplet()
     return {
            Parts = {}
       }
end

local ChatRef = {}
function makeChat(chatText: string, role: "user" | "model" | nil?)
	
        local UUID = HttpService:GenerateGUID()
  
        ChatRef[UUID] = createChatTemplet()

	table.insert( 
                ChatRef[UUID].parts, 
                1, 
		UUID = chatText
	})

     return UUID
end

Now instead of ref itself you are storing a ref to another table.

So now you just need to store the UUID to short ref the text or something of that matter.

So if you get whats going on here, we have the core storage ref of the Table so we can work backwards from the UUID provided or we can work through our list and find it via UUID as well, but anytime you want to ref a position in ourselves we use the UUID that we return.

We also then for ease, I am just using it to hash directly to the text we want since might as well. Since I am assuming we are trying to get the text ?

2 Likes

Also, when you call something a “TEMPLATE”
Generally speaking you are DEEP cloning from that, which is why
I made the function that generate a new table each time because
table does not have a built in deep cloning ability.

Templates are generally used as your structural core you deep clone from before you fill out, you you are reading from the template as you fill it out. Just sayin

thanks for reminding me that error, i was so confused for a whole day, just trying to get this bug fixed.

i use this json for a game that uses Gemini AI, I use the rest API since there’s no official “lua” sdk online.

image

now its working, just expected.
thanks a lot, should’ve more careful next time :sweat_smile:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.