Roblox Studio error

attempt to iterate over a nil value

What attempt to iterate over a nil value means in Roblox Studio, the three things that cause it with the code that triggers each, and the fix for each one.

Updated 23 October 20263 min readErrorLuau

In short

for key, value in something do needs a table, such as the list GetChildren() returns. This error says something was nil. Find out why that table is missing: data that has not loaded, a function that did not return a table, or an attribute, which can never hold one. Then check it before the loop, or loop over an empty table instead.

On this page
  1. What it means
  2. Causes and fixes
  3. Fix it with RoCode
  4. Find the line
  5. Questions
  6. Sources

What the message means

Output (example)
ServerScriptService.Inventory:21: attempt to iterate over a nil value

Other forms of the same message:

  • attempt to iterate over a number value
  • attempt to iterate over a string value

Luau lets you loop over a table directly (for k, v in inventory do). When the value after in is not a table, it has nothing to walk through and stops. With pairs(x) or ipairs(x) the same mistake gives invalid argument #1 to 'pairs' (table expected, got nil) instead.

The type in the message is what Luau found: nil most of the time, number or string when you looped over a single value by mistake.

Causes and fixes

Three things cause this error in practice. Each one below has the smallest code that triggers it, then the fix.

Player data has not loaded yet

If a table only exists after a data store load, code that runs earlier (a shop opening, a RemoteEvent) loops over nil.

Breaks Script in ServerScriptService named Inventory
local inventories = {}

local function listItems(userId)
	-- before the load sets inventories[userId]: attempt to iterate over a nil value
	for itemName, count in inventories[userId] do
		print(itemName, count)
	end
end

listItems(12345)

Check the table first and return early, or fall back to an empty table with or {} when "nothing yet" is a fine answer.

Fixed Script in ServerScriptService named Inventory
local inventories: { [number]: { [string]: number } } = {}

local function listItems(userId: number)
	local inventory = inventories[userId]
	if not inventory then
		warn(`[Inventory] not loaded for {userId}`)
		return
	end
	for itemName, count in inventory do
		print(itemName, count)
	end
end

listItems(12345)

A function did not return the table

A helper that builds a list but forgets return gives back nil. So does one that returns early on some path.

Breaks Script in ServerScriptService named Spawns
local function getSpawns()
	local spawns = {}
	for _, child in workspace:GetChildren() do
		if child:IsA("SpawnLocation") then
			table.insert(spawns, child)
		end
	end
	-- forgot: return spawns
end

for _, spawnPart in getSpawns() do
	print(spawnPart.Name)
end

Return the table on every path. A return type in the function signature makes the Script Editor warn you when one path returns nothing.

Fixed Script in ServerScriptService named Spawns
local function getSpawns(): { SpawnLocation }
	local spawns: { SpawnLocation } = {}
	for _, child in workspace:GetChildren() do
		if child:IsA("SpawnLocation") then
			table.insert(spawns, child)
		end
	end
	return spawns
end

for _, spawnPart in getSpawns() do
	print(spawnPart.Name)
end

An attribute was looped over

Attributes hold single values (text, numbers, booleans and a few Roblox types), never tables. GetAttribute returns nil when the attribute is not set, and a list saved as text is a string, so looping over it fails with nil or string in the message.

Breaks Script in ServerScriptService named Badges
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
	-- not set yet: attempt to iterate over a nil value
	for _, badge in player:GetAttribute("Badges") do
		print(badge)
	end
end)

Keep lists in a table on the server (or in a folder of values). If you must store a list in an attribute, save it as JSON text and decode it, checking the type at each step.

Fixed Script in ServerScriptService named Badges
local HttpService = game:GetService("HttpService")
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player: Player)
	local raw = player:GetAttribute("Badges")
	if typeof(raw) ~= "string" then
		return -- no badges saved yet
	end
	local ok, list = pcall(HttpService.JSONDecode, HttpService, raw)
	if ok and typeof(list) == "table" then
		for _, badge in list do
			print(badge)
		end
	end
end)

Fix it in your place

Paste the error, RoCode fixes it in your place

Copy the line from Output and paste it here. RoCode opens the script it names in the place you have open in Studio, works out which of the causes above it is, and edits the code there instead of handing you a snippet to paste.

For example: ServerScriptService.Inventory:21: attempt to iterate over a nil value

RoCode is an AI agent for Roblox Studio: it reads the scripts in the place you have open, finds the line and edits it there, and every change is an undo point. It runs on Windows or macOS with a desktop browser. Free to start, with free credits every day.

How to find the line that causes it

  1. Open Output (Window menu, or the Script tab), clear it with Ctrl+K (⌘K on Mac), and press Play.
  2. Find the first red line. It starts with the script's place in the Explorer and the line number, such as ServerScriptService.Shop:12:.
  3. Click the red line. Studio opens that script with the cursor on the failing line.
  4. Read the lines between Stack Begin and Stack End under it: they list the calls that led there, newest first, so you can see which function called the broken one.
  5. Still not sure which value is wrong? Add print(typeof(x), x) just above the line, or set a breakpoint on it and read the values in the Watch window.

Questions

Do I need pairs or ipairs in Roblox?

No. Luau can loop over a table directly: for key, value in t do. ipairs is still useful when you want to stop at the first gap in a list.

What is the difference from table expected, got nil?

Same mistake, different wording. Looping over nil directly says attempt to iterate over a nil value; passing nil to pairs or ipairs says invalid argument #1 to 'pairs' (table expected, got nil).

How do I loop over the parts in a folder?

Use folder:GetChildren() for the direct children, or folder:GetDescendants() for everything inside, including parts inside models.

Can RoCode fix it?

Yes. Paste the Output line into RoCode. It finds why the table is missing in the script in your open place and adds the check, the return or the GetChildren call.

Sources and further reading

How the code was checked: every block marked Fixed passes Luau's strict type checker against Roblox's API definitions (luau-lsp, 23 October 2026), and every block marked Breaks compiles and fails only when it runs. The message wording was checked by running the broken code with the Luau command line tool and against the message strings in Roblox Studio itself on 23 October 2026. A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.

Stop hunting errors line by line.

RoCode reads the scripts in your open place, fixes the error where it happens and tells you what it changed. Free every day, no card required.