How to Fix 'attempt to compare number with nil' in Roblox
Last updated:
Quick answer: 'Attempt to compare number with nil' means one side of a <, >, <= or >= comparison is a number and the other is nil. Find which value is nil (a missing attribute, a wrong child name, a value not loaded yet), then give it a default with 'or', or check it with 'if value then' before comparing.
The "attempt to compare number with nil" error happens when you use <, >, <= or >= and one side of the comparison is a number while the other side is nil. Luau can only order two numbers or two strings. If one of them is missing, it stops with this error instead of guessing what you meant.
You will also see the mirrored form, attempt to compare nil with number. The order in the message just tells you which side was nil: the first type named is the left operand, the second is the right operand.
What the Error Looks Like
local price = shopItem:GetAttribute("Price") -- nil if the attribute was never set
local coins = 250
if coins >= price then -- attempt to compare number with nil
print("Can afford it")
end
GetAttribute returned nil because no attribute named Price exists on that object. The comparison then had a number on one side and nil on the other.
The Most Common Causes
A misspelled or missing attribute. Attribute names are case-sensitive. GetAttribute("price") and GetAttribute("Price") are two different lookups, and a typo returns nil with no warning.
A table key that does not exist. Reading a key that is not in a table gives nil, not an error:
local weapons = {
Sword = { damage = 10 },
Bow = { damage = 6 },
}
local damage = weapons.Spear.damage -- this indexes nil, a different error
local level = weapons.Sword.level -- nil, no error yet
if level > 5 then end -- attempt to compare nil with number
A value that has not loaded or been set yet. Data from a DataStore, a leaderstat created by another script, or a value waiting on a RemoteEvent can be nil when your code first runs. If you want to understand why timing matters, see fixing attempt to index nil, which covers the same loading problem.
A function that returns nothing on some paths. If a function sometimes forgets to return, the caller receives nil:
local function getLevel(xp)
if xp > 1000 then
return 5
elseif xp > 100 then
return 2
end
-- falls off the end: returns nil for xp <= 100
end
if getLevel(50) > 1 then end -- attempt to compare nil with number
Comparing a string to a number. This one gives a different message (attempt to compare string with number), but people mix the two up. Text read from a TextBox is a string. Convert it with tonumber() first.
How to Find the Nil Value
- Click the error line in the Output window. Studio takes you to the exact comparison.
- Print both sides right before it, with their types:
print("left:", coins, typeof(coins))
print("right:", price, typeof(price))
if coins >= price then end
- Whichever one prints
nil nilis the problem. Trace it back to where it was assigned and ask why nothing was stored there.
Printing the type with typeof is useful because a value can look right in the Output but actually be a string like "100".
Fix 1: Provide a Default With or
When a missing value has a sensible fallback, supply it at the point you read it:
local price = shopItem:GetAttribute("Price") or 0
local level = weapons.Sword.level or 1
if level > 5 then
print("High level weapon")
end
a or b returns b whenever a is nil or false. For numbers this is safe because 0 is truthy in Luau, so a real zero will not be replaced by the default.
Fix 2: Check Before Comparing
When a missing value means the code should not run at all, guard it:
local price = shopItem:GetAttribute("Price")
if price == nil then
warn("Shop item has no Price attribute:", shopItem:GetFullName())
return
end
if coins >= price then
buy(shopItem)
end
The warning matters. A silent return hides the bug and you will spend an hour wondering why the shop does nothing.
Fix 3: Wait for the Value to Exist
If the value is created by another script, wait for the object instead of reading it once:
local leaderstats = player:WaitForChild("leaderstats", 10)
local coins = leaderstats and leaderstats:WaitForChild("Coins", 10)
if coins then
if coins.Value >= 100 then
print("Enough coins")
end
end
Always pass a timeout. Without one, a missing object stalls your script forever and you get the infinite yield warning instead; see the infinite yield fix.
Fix 4: Make Functions Return a Value on Every Path
local function getLevel(xp: number): number
if xp > 1000 then
return 5
elseif xp > 100 then
return 2
end
return 1
end
Adding a return type annotation helps. Studio's type checker will flag a function that does not return a number on every path before you even run the game.
Common Mistakes
- Comparing
.Valueof the wrong object.coins.Valueon an IntValue is a number, butcoinsitself is an Instance.coins >= 100givesattempt to compare Instance with number. - Using
wait()to "fix" timing. Adding a delay might hide the error on your machine and fail on a slow server. Wait for the actual object or value instead, not for a fixed number of seconds. Our task.wait vs wait comparison explains the modern replacement when you do need a delay. - Defaulting everything to 0. If a missing price silently becomes
0, every item becomes free. Only use defaults where the fallback is truly safe. - Ignoring DataStore failures. Loaded data can be nil for new players or when a request fails. Wrap the call in pcall (see what pcall does) and apply defaults for new players before you compare any numbers.
Practice It
Nil comparisons show up in almost every economy, level and shop system, so it pays to get fast at spotting them. The Luablox lessons include exercises where you fix broken comparisons, and the problems page has short drills you can run directly in the browser.
Frequently asked questions
What does 'attempt to compare number with nil' mean?
One side of a <, >, <= or >= comparison is a number and the other side is nil. Luau cannot order a number against nothing, so it raises an error. The cause is almost always a value that was never set or has not loaded yet.
What is the difference between 'compare number with nil' and 'compare nil with number'?
They are the same bug seen from different sides. The message lists the left operand type first and the right operand type second, so 'compare nil with number' means the left side was nil, and 'compare number with nil' means the right side was nil.
Does == nil also throw this error?
No. Equality checks work with any types, so value == nil is safe and returns true or false. Only the ordering operators <, >, <= and >= require both sides to be numbers (or both strings).
Is it better to use 'or 0' or an if check?
Use 'or' when a default value is genuinely correct, like a missing level meaning level 1. Use an if check with a warn when a missing value indicates a real bug, such as a shop item without a price, so you notice and fix it instead of hiding it.
Learn core Roblox scripting and Luau programming concepts, including: attempt to compare number with nil, attempt to compare nil with number, attempt to compare number with nil roblox, attempt to compare nil < number, luau compare nil error.