попытка вызвать nil значение (field, global, method): как это исправить

Получаете 'attempt to call a nil value' в FiveM? Что означают варианты field, global и method и как исправить опечатку, отсутствующий export или ошибку двоеточие-точка.

В консоли:

text
SCRIPT ERROR: @my_script/server/main.lua:42: attempt to call a nil value (field 'GetPlayerFromId')
SCRIPT ERROR: @my_script/client/main.lua:17: attempt to call a nil value (global 'DrawText3D')
SCRIPT ERROR: @my_script/client/main.lua:63: attempt to call a nil value (method 'Notify')

Lua говорит вам, что строка попытался запустить функцию, которая не существует. В этой статье объясняются три варианта, обычные причины и способ исправления каждого.

Что означает ошибка

В Lua отсутствующее имя само по себе не является ошибкой: чтение его даёт nil. Ошибка появляется только когда вы ставите скобки после него, потому что вы не можете запустить nil. Текст в скобках говорит, как скрипт достиг отсутствующей функции:

  • attempt to call a nil value (global 'X'): простой вызов типа X(). Функция не определена ни в одном месте, которое скрипт может видеть.
  • attempt to call a nil value (field 'X'): вызов через таблицу типа ESX.X() или QBCore.Functions.X(). Таблица существует, но в ней нет записи X.
  • attempt to call a nil value (method 'X'): вызов с двоеточием типа obj:X(). Объект существует, но не имеет метода X.

Файл и строка перед сообщением (@my_script/server/main.lua:42) — это строка, которая делает вызов. Если вы не уверены, как читать остальную часть вывода, см. как прочитать ошибку скрипта FiveM.

1. Опечатка в имени

Lua чувствительна к регистру. GetPlayerFromId и getPlayerFromId — это два разных имени, и то же самое с TriggerClientEvent и TriggerclientEvent. Сравните имя в ошибке с документацией фреймворка, букву за буквой.

2. Функция не существует в вашей версии

Фреймворки переименовывают и удаляют функции. Это наиболее частая причина для скриптов, которые были написаны для другой версии вашего фреймворка.

lua
-- an old call that may be gone on your version
local xPlayer = ESX.GetPlayerFromId(source)
xPlayer.getInventoryItem('bread')

Проверьте, что действительно предлагает ваш фреймворк. Выведите таблицу, чтобы увидеть её записи:

lua
for name, value in pairs(ESX) do
    print(name, type(value))
end

Если функция, которая вам нужна, отсутствует в списке, скрипт и фреймворк не совпадают. Обновите фреймворк, обновите скрипт или замените вызов на тот, который есть в вашей версии.

3. Export отсутствует

Exports — это функции, которые предоставляет другой ресурс. Когда ресурс остановлен, не запустился или не экспортирует это имя, вызов не удаётся.

lua
local core = exports['qb-core']:GetCoreObject()
core.Functions.GetPlayer(source)

Если ресурс не запущен, FiveM печатает No such export вместо этого. Если он работает, но имя export неправильно, вы можете получить nil field. Запустите ресурс первым в server.cfg и проверьте точные имена экспортов в его документации или fxmanifest.lua. Две связанные исправления: ESX is nil и No such export getSharedObject.

4. Двоеточие против точки

Двоеточие передаёт объект как скрытый первый аргумент. Точка не делает этого. Смешивание их даёт либо эту ошибку, либо неправильные аргументы.

lua
-- calls the method with the object as first argument
player:Notify('hello')

-- calls a plain function stored in a table
Utils.Notify('hello')

Если ошибка говорит (method 'Notify'), объект не имеет записи Notify: используйте форму с точкой, если функция находится в таблице библиотеки, или проверьте, что объект действительно то, что вы думаете. С ox_lib, например, lib.notify({...}) — это вызов с точкой на таблице lib.

5. Функция определена позже или в другом файле

Локальная функция должна быть определена перед строкой, которая её вызывает, в том же файле. Функция, определённая в другом файле, видна только если она глобальна и только если этот файл загружен той же стороной (клиент или сервер) одного и того же ресурса.

lua
-- fails: DoThing is defined below the call
DoThing()

local function DoThing()
    print('hi')
end

Переместите определение выше вызова или объявите его первым с помощью local DoThing и присвойте его позже. Также проверьте fxmanifest.lua: файл, который не указан в client_scripts, server_scripts или shared_scripts, никогда не загружается, поэтому его функции никогда не существуют.

lua
client_scripts { 'client/*.lua' }
server_scripts { 'server/*.lua' }
shared_scripts { '@ox_lib/init.lua', 'config.lua' }

6. Функция клиента используется на сервере или наоборот

Многие нативы и функции фреймворка существуют только на одной стороне. PlayerPedId только на клиенте, а GetPlayerIdentifiers только на сервере. Таблицы фреймворка также различаются: ESX.GetPlayerFromId — это серверная функция, а клиент использует ESX.GetPlayerData. Скрипт, который запускается в shared_scripts, выполняется с обеих сторон, поэтому вызов, который работает с одной стороны, аварийно завершается с другой.

Совет: самый быстрый тест — это print прямо перед неудачной строкой: print(type(ESX.GetPlayerFromId)). Если он выводит nil, функция отсутствует. Если он выводит function, реальная проблема где-то ещё.

Защитите это, пока вы отлаживаете

Проверьте перед вызовом, чтобы получить ясное сообщение вместо краха:

lua
local fn = ESX.GetPlayerFromId
if type(fn) ~= 'function' then
    print('GetPlayerFromId is missing: check the ESX version')
    return
end

Не оставляйте охранников вроде этого на месте как исправления. Они скрывают реальную проблему, которая является скриптом и фреймворком, которые не совпадают.

Чеклист

Симптом Исправление
(global 'X') Функция не определена в файле или никогда не загружена: проверьте манифест и порядок определения
(field 'X') Таблица не имеет такой записи: проверьте орфографию и версию фреймворка
(method 'X') Неправильный объект или двоеточие используется вместо точки: проверьте, что переменная содержит
Работает только с одной стороны Функция существует только на клиенте или только на сервере
Ошибка после обновления фреймворка Замените удалённую функцию на новую или обновите скрипт
Вызов export возвращает nil Запустите предоставляющий ресурс первым и проверьте имя export

Короткие ответы

Что означает 'attempt to call a nil value'?

Скрипт попытался запустить что-то как функцию, но имя содержит nil, так что там ничего нет для запуска. Имя внутри скобок говорит вам, какая функция отсутствует.

Каков разница между field, global и method в этой ошибке?

global — это простое имя типа Foo(), field — это запись таблицы типа Config.Foo() или ESX.Foo(), а method — это вызов с двоеточием типа obj:Foo(). Это только говорит вам, как была достигнута отсутствующая функция.

Может ли неправильная версия фреймворка вызвать это?

Да. Скрипт, написанный для старой или новой версии ESX, QBCore или QBox, может вызывать функцию, которую ваша версия переименовала или удалила, что оставляет nil позади.

Скрипты без этой проблемы

Advanced BoostingУгон машин на заказ через планшет: контракты от класса D до S+, команды и живая очередь.Смотреть скрипт →Quest CreatorВизуальный редактор квестов и диалогов с NPC — узел за узлом прямо в игре.Смотреть скрипт →Item Creator V2Создавайте используемые предметы с анимациями, пропами, эффектами и не только — без кода.Смотреть скрипт →

Читайте также