attempt to compare number with nil / arithmetic on a nil value: fix
Fix 'attempt to compare number with nil' and 'arithmetic on a nil value' in FiveM: unloaded player data, missing config values, tonumber and safe defaults with `or`.
Console output:
SCRIPT ERROR: @my_script/server/main.lua:58: attempt to compare number with nil
SCRIPT ERROR: @my_script/client/main.lua:91: attempt to perform arithmetic on a nil value (field 'money')A line of the script uses a value that does not exist yet in a comparison or a calculation. Here is what usually leaves the value empty, and how to make the script safe.
What the error means
Lua gives you nil for any variable or table entry that has no value. Comparing (<, >, <=) or calculating (+, -, *, /) with nil stops the script with one of these messages:
attempt to compare number with nil(orattempt to compare nil with number): one side of the comparison isnil.attempt to perform arithmetic on a nil value: a calculation uses anilvariable. When Lua knows the name, it adds it, like(field 'money')or(local 'price').
The line number in the message is the line with the comparison or the sum. The nil is one of the values on that line. Print them to see which one:
print('price', price, type(price))
print('count', count, type(count))
if price > count then
-- ...
end1. Player data is not loaded yet
The most common cause: the script reads the player before the framework has finished loading them, for example in the first lines of a file, or in a thread that starts at once.
-- runs too early on the client: money is nil
local money = ESX.GetPlayerData().money
if money > 100 then
-- ...
endWait for the framework's loaded event, and read the data from there:
-- ESX client
local PlayerData = {}
RegisterNetEvent('esx:playerLoaded', function(xPlayer)
PlayerData = xPlayer
end)-- QBCore client
local QBCore = exports['qb-core']:GetCoreObject()
local PlayerData = {}
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
PlayerData = QBCore.Functions.GetPlayerData()
end)On the server, a player object can also be nil when the id is wrong or the player has left. Check it before you use it:
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer then return endlocal Player = QBCore.Functions.GetPlayer(source)
if not Player then return endOn QBox, the equivalent is exports.qbx_core:GetPlayer(source), with the same nil check.
Tip: if the script is restarted while you are on the server,
playerLoadedhas already fired and will not fire again. Read the data once when the resource starts as well.
2. A config value is missing
You added a line to config.lua that the script does not have, or the script reads a key that your older config does not contain. After an update, an old config.lua is a very common cause.
-- config.lua of the old version has no Config.Price
if playerMoney >= Config.Price then
-- ...
endCompare your config with the one shipped with the new version, and add the missing keys. In your own code, give every setting a default:
local price = Config.Price or 1003. The value is a string, not a number
Values from a database, an input box in a menu or a JSON message often arrive as text. Comparing a string with a number gives a different error (attempt to compare number with string), but a conversion that fails gives you nil, which brings this error back. tonumber converts, and returns nil when it cannot:
local amount = tonumber(data.amount)
if not amount then
return -- not a number: stop here
end4. Use or for a default
or returns the right side when the left side is nil (or false). It is the shortest way to make a calculation safe:
local count = tonumber(data.count) or 0
local total = (item.price or 0) * countUse it where a missing value really can mean zero, such as an optional bonus. Where a missing value is a bug, for example a price that must exist, stop with a clear message instead of hiding it:
local price = Config.Items[name] and Config.Items[name].price
if not price then
print(('no price set for %s'):format(name))
return
end5. A database or callback result is empty
A query that finds no row gives nil or an empty table. Reading a column from it fails:
local row = MySQL.single.await('SELECT balance FROM bank WHERE owner = ?', { identifier })
if row.balance > 0 then -- row is nil when the player has no row
-- ...
endCheck the row first:
local row = MySQL.single.await('SELECT balance FROM bank WHERE owner = ?', { identifier })
local balance = row and row.balance or 0The same goes for server callbacks: the answer can be nil if the callback was not found or returned nothing. If your script waits on a callback, handle that case. Related: attempt to call a nil value is the sister error when a function, not a value, is missing.
6. A typo in a field name
xPlayer.money and xPlayer.Money are different. So are price and Price. The error message often names the field: check its spelling against the framework documentation or against the table you print with print(json.encode(data)).
Checklist
| Symptom | Fix |
|---|---|
| Error right after joining | Wait for the player loaded event before reading player data |
xPlayer or Player is nil on the server |
Check if not xPlayer then return end and the source id |
| Error after updating a script | Add the new keys of the shipped config.lua to yours |
| Value comes from a menu or JSON | Convert with tonumber(value) and check it is not nil |
| A value may be missing on purpose | Use value or 0 as a default |
| Database query returns nothing | Check the row is not nil before reading its columns |
| Field is nil even though it should exist | Check the spelling and capital letters |
Quick answers
What does 'attempt to compare number with nil' mean?
A line compares a number with something that has no value, like price > 100 when price is nil. Find which variable is nil and why it was never set.
How do I give a variable a default value in Lua?
Use or: local count = tonumber(value) or 0. If the value is nil or not a number, count becomes 0.
Why does it only happen right after I join the server?
The script reads player data before the framework has loaded it. Wait for the player loaded event, or check that the player object is not nil before you read from it.


