попытка сравнить число с nil / арифметика на nil значение: исправление
Исправить 'attempt to compare number with nil' и 'arithmetic on a nil value' в FiveM: невагруженные данные игрока, отсутствующие значения конфигурации, tonumber и безопасные значения по умолчанию с `or`.
Вывод консоли:
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')Строка скрипта использует значение, которое ещё не существует в сравнении или расчёте. Вот что обычно оставляет значение пустым и как сделать скрипт безопасным.
Что означает ошибка
Lua даёт вам nil для любой переменной или записи таблицы, которая не имеет значения. Сравнение (<, >, <=) или расчёт (+, -, *, /) с nil останавливает скрипт с одним из этих сообщений:
attempt to compare number with nil(илиattempt to compare nil with number): одна сторона сравнения этоnil.attempt to perform arithmetic on a nil value: расчёт использует переменнуюnil. Когда Lua знает имя, он добавляет его, как(field 'money')или(local 'price').
Номер строки в сообщении — это строка со сравнением или суммой. nil — это один из значений на этой строке. Выведите их, чтобы увидеть, какой:
print('price', price, type(price))
print('count', count, type(count))
if price > count then
-- ...
end1. Данные игрока ещё не загружены
Самая частая причина: скрипт читает игрока до того, как фреймворк закончил их загружать, например в первых строках файла или в потоке, который запускается сразу.
-- runs too early on the client: money is nil
local money = ESX.GetPlayerData().money
if money > 100 then
-- ...
endДождитесь события загрузки фреймворка и прочитайте данные оттуда:
-- 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)На сервере, объект игрока также может быть nil, когда идентификатор неправильный или игрок уехал. Проверьте это перед его использованием:
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer then return endlocal Player = QBCore.Functions.GetPlayer(source)
if not Player then return endНа QBox, эквивалент — это exports.qbx_core:GetPlayer(source), с той же проверкой nil.
Совет: если скрипт перезагружается, пока вы находитесь на сервере,
playerLoadedуже сработало и не сработает снова. Прочитайте данные один раз, когда ресурс запускается.
2. Отсутствует значение конфигурации
Вы добавили строку в config.lua, которую не имеет скрипт, или скрипт читает ключ, который ваша более старая конфигурация не содержит. После обновления, старый config.lua — это очень частая причина.
-- config.lua of the old version has no Config.Price
if playerMoney >= Config.Price then
-- ...
endСравните вашу конфиг с той, которая поставляется с новой версией, и добавьте отсутствующие ключи. В вашем собственном коде дайте каждой настройке значение по умолчанию:
local price = Config.Price or 1003. Значение — это строка, а не число
Значения из базы данных, входного поля в меню или сообщения JSON часто приходят как текст. Сравнение строки с числом даёт другую ошибку (attempt to compare number with string), но преобразование, которое не удаётся, даёт вам nil, что приносит эту ошибку обратно. tonumber преобразует и возвращает nil когда не может:
local amount = tonumber(data.amount)
if not amount then
return -- not a number: stop here
end4. Используйте or для значения по умолчанию
or возвращает правую сторону, когда левая сторона nil (или false). Это самый короткий способ сделать расчёт безопасным:
local count = tonumber(data.count) or 0
local total = (item.price or 0) * countИспользуйте его, где отсутствующее значение действительно может означать ноль, например, необязательный бонус. Где отсутствующее значение — это ошибка, например, цена, которая должна существовать, остановитесь с ясным сообщением вместо его скрытия:
local price = Config.Items[name] and Config.Items[name].price
if not price then
print(('no price set for %s'):format(name))
return
end5. Результат запроса к базе данных или обратного вызова пуст
Запрос, который не находит строку, даёт nil или пустую таблицу. Чтение столбца из неё не удаётся:
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
-- ...
endПроверьте строку в первую очередь:
local row = MySQL.single.await('SELECT balance FROM bank WHERE owner = ?', { identifier })
local balance = row and row.balance or 0То же самое относится к серверным обратным вызовам: ответ может быть nil, если обратный вызов не был найден или ничего не вернул. Если ваш скрипт ждёт обратного вызова, обработайте этот случай. Связанное: attempt to call a nil value — это сестра ошибка, когда функция, а не значение, отсутствует.
6. Опечатка в имени поля
xPlayer.money и xPlayer.Money — разные. Как и price и Price. Сообщение об ошибке часто называет поле: проверьте его орфографию против документации фреймворка или против таблицы, которую вы выводите с помощью print(json.encode(data)).
Чеклист
| Симптом | Исправление |
|---|---|
| Ошибка сразу после присоединения | Дождитесь события загрузки игрока перед чтением данных игрока |
xPlayer или Player это nil на сервере |
Проверьте if not xPlayer then return end и источник id |
| Ошибка после обновления скрипта | Добавьте новые ключи поставляемого config.lua в ваши |
| Значение поступает из меню или JSON | Преобразуйте с помощью tonumber(value) и проверьте, что это не nil |
| Значение может отсутствовать специально | Используйте value or 0 как значение по умолчанию |
| Запрос базы данных не возвращает ничего | Проверьте, что строка не nil перед чтением её столбцов |
| Поле это nil, даже если оно должно существовать | Проверьте орфографию и заглавные буквы |
Короткие ответы
Что означает 'attempt to compare number with nil'?
Строка сравнивает число с чем-то, что не имеет значения, типа price > 100, когда price это nil. Найдите, какая переменная это nil и почему её никогда не устанавливали.
Как дать переменной значение по умолчанию в Lua?
Используйте or: local count = tonumber(value) or 0. Если значение это nil или не число, count становится 0.
Почему это происходит только сразу после присоединения к серверу?
Скрипт читает данные игрока до того, как фреймворк их загрузил. Дождитесь события загрузки игрока или проверьте, что объект игрока не nil перед чтением из него.


