In short
An event handler triggered its own event. For example, a Changed handler that changes the value it watches fires Changed again, which runs the handler again, and so on. Roblox stops the chain after a fixed depth and prints this, naming the object class and the event (IntValue.Changed). Make the handler leave the value alone when it is already right, or change it somewhere the event does not watch.
What the message means
Maximum event re-entrancy depth exceeded for IntValue.Changed
Other forms of the same message:
Maximum event re-entrancy depth exceeded for Humanoid.HealthChanged
Re-entrancy means an event firing again while its own handler is still running. A little is normal; endless re-entry is a bug, and Roblox cuts it off instead of letting it freeze the game.
The message names the event, not your script. Search your scripts for handlers on that event (for example .Changed:Connect) that also set the property it watches.
Causes and fixes
Three things cause this error in practice. Each one below has the smallest code that triggers it, then the fix.
- A Changed handler changes the same value
- A Text handler rewrites the Text it listens to
- Two handlers keep changing each other
A Changed handler changes the same value
A bonus that adds to a value from inside that value's own Changed handler is the classic case. Every change fires Changed again, which adds again.
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
local coins = player:WaitForChild("leaderstats"):WaitForChild("Coins")
coins.Changed:Connect(function()
-- a "bonus coin" on every change fires Changed again, forever
coins.Value += 1
end)
end)
Apply the change where the value is set in the first place, in one function every script calls, instead of reacting to it.
local BONUS = 1
local function addCoins(coins: IntValue, amount: number)
coins.Value += amount + BONUS
end
local coins = Instance.new("IntValue")
addCoins(coins, 10)
print(coins.Value) -- 11
Clamping inside Changed (if value > MAX then coins.Value = MAX end) is safe, because the second set does not change the value again, so the chain stops after one step.
A Text handler rewrites the Text it listens to
Formatting a TextBox as the player types, by setting Text inside its own GetPropertyChangedSignal("Text") handler, fires the handler again with the new text. If the formatting always adds something, it never settles.
local box = script.Parent
box:GetPropertyChangedSignal("Text"):Connect(function()
-- adds "$" every time, which changes Text again, forever
box.Text = "$" .. box.Text
end)
Only set Text when the formatted text is different from what is already there, so the second round changes nothing and the chain ends.
local box = script.Parent :: TextBox
box:GetPropertyChangedSignal("Text"):Connect(function()
local digits = box.Text:gsub("%D", "")
local formatted = "$" .. digits
if box.Text ~= formatted then
box.Text = formatted
end
end)
Two handlers keep changing each other
A handler on A sets B, and a handler on B sets A, for example two values kept in sync with a conversion that never settles. Neither looks wrong on its own.
local celsius = Instance.new("NumberValue")
local fahrenheit = Instance.new("NumberValue")
celsius.Changed:Connect(function(c)
fahrenheit.Value = c * 9 / 5 + 32
end)
fahrenheit.Changed:Connect(function(f)
-- adds 0.1 each round, so the values never settle
celsius.Value = (f - 32) * 5 / 9 + 0.1
end)
celsius.Value = 20
Keep one source of truth and compute the other from it, in one direction only.
local celsius = Instance.new("NumberValue")
local fahrenheit = Instance.new("NumberValue")
-- celsius is the source; fahrenheit only follows it
celsius.Changed:Connect(function(c: number)
fahrenheit.Value = c * 9 / 5 + 32
end)
celsius.Value = 20
print(fahrenheit.Value) -- 68
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.
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
- The message names the class and event, for example
IntValue.Changed. Search all scripts (Ctrl+Shift+F) for that event, such as.Changed:ConnectorHealthChanged. - In each handler you find, look for a line that sets the property the event watches.
- Recent Studio builds can add the function and line it was calling to the message; if yours does, start there.
Questions
What is the re-entrancy depth?
How many times an event can fire again from inside its own handlers before Roblox stops it. Normal code never comes near it; reaching it means a loop.
Does setting a value to the same value fire Changed?
For value objects such as IntValue, no: Changed fires when the value actually changes. That is why setting it only when it is wrong ends the loop.
Is this the same as stack overflow?
They are cousins. Stack overflow is a function calling itself; this is an event setting itself off. The fix is the same idea: give the repeat a way to stop.
Can RoCode fix it?
Yes. Paste the Output line into RoCode. It searches the scripts in your open place for the handler that sets off its own event and rewrites it.
Sources and further reading
- Roblox Creator Docs: IntValue.Changed
- Roblox Creator Docs: Humanoid.HealthChanged
- Roblox DevForum: Maximum event re-entrancy depth exceeded for Humanoid.HealthChanged
- Roblox DevForum: How would I have a Value not be affected with Changed?
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 against the message format strings in Roblox Studio itself (macOS build of 13 October 2026) on 23 October 2026; recent builds can also name the function and line it was calling. A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.