attempt to index a nil value (local 'xPlayer'): исправление ESX

xPlayer равна nil в вашем скрипте ESX? Почему ESX.GetPlayerFromId(source) возвращает nil: игрок не загружен, source потерян после Wait, строковые id, playerDropped. С паттернами охраны.

Консоль сервера показывает:

text
SCRIPT ERROR: @my_script/server/main.lua:23: attempt to index a nil value (local 'xPlayer')
lua
local xPlayer = ESX.GetPlayerFromId(source)
xPlayer.addMoney(100)   -- xPlayer is nil

ESX.GetPlayerFromId не нашла игрока для этого id и вернула nil, и следующая строка индексировала его. Вызов в порядке. Id, которые вы ей дали, не совпадает с загруженным игроком ESX. Вот обычные причины и как защитить каждую.

1. Игрок еще не загружен

Игрок подключен к серверу, прежде чем ESX закончит загрузку их персонажа. Во время этого промежутка и пока открыт экран мультииграка, ESX.GetPlayerFromId(source) возвращает nil.

Это попадает в код, который запускается рано, такой как общие события FiveM playerJoining или playerConnecting, или поток, который запускается в момент запуска вашего ресурса.

Используйте событие ESX, которое срабатывает, когда игрок готов, на сервере:

lua
AddEventHandler('esx:playerLoaded', function(playerId, xPlayer, isNew)
    print(('%s is loaded'):format(xPlayer.getName()))
end)

На клиенте то же имя события говорит вашему клиентскому скрипту, что игрок может быть использован:

lua
RegisterNetEvent('esx:playerLoaded', function(xPlayer)
    PlayerLoaded = true
end)

Если ваш скрипт может быть перезагружен, пока игроки в сети, это событие уже для них сработало. При запуске зациклитесь над игроками, которые уже есть у ESX:

lua
CreateThread(function()
    for _, playerId in ipairs(GetPlayers()) do
        local xPlayer = ESX.GetPlayerFromId(tonumber(playerId))
        if xPlayer then
            -- set up the player
        end
    end
end)

2. source изменился после Wait

source — это специальное глобальное значение, которое FiveM устанавливает для работающего события. Если вы ждете внутри обработчика, другое событие может запуститься тем временем и source больше не принадлежит вашему игроку.

lua
RegisterNetEvent('my_script:buy', function(item)
    Wait(500)
    local xPlayer = ESX.GetPlayerFromId(source)   -- source may be someone else, or invalid
end)

Храните его в локальном перед чем-либо еще:

lua
RegisterNetEvent('my_script:buy', function(item)
    local src = source
    Wait(500)

    local xPlayer = ESX.GetPlayerFromId(src)
    if not xPlayer then return end
end)

То же применяется внутри обратного вызова или функции, которой вы передаете source позже: передайте сохраненное значение, а не глобальное.

3. Id неправильный

ESX.GetPlayerFromId нужна серверная id как число игрока, который в сети.

  • Строковая id. Аргументы команды — это текст. ESX.GetPlayerFromId(args[1]) может вернуть nil, где ESX.GetPlayerFromId(tonumber(args[1])) работает.
  • Неправильная id с клиента. На клиенте PlayerId() — это локальный индекс, а не серверная id. Серверная id — это GetPlayerServerId(PlayerId()). Отправка неправильной дает игрока, которого не существует, или неправильного игрока.
  • Консоль. Команда, введенная в консоль сервера, имеет source равный 0, что не является игроком.
  • Id из поиска по идентификатору. ESX.GetPlayerFromIdentifier(identifier) только находит игроков, которые в сети. Для оффлайн игрока читайте базу данных вместо этого, смотрите oxmysql queries guide.
lua
RegisterCommand('givecash', function(source, args)
    local target = tonumber(args[1])
    local amount = tonumber(args[2])
    if not target or not amount then
        return print('Usage: /givecash [id] [amount]')
    end

    local xTarget = ESX.GetPlayerFromId(target)
    if not xTarget then
        return print('Player not found or not loaded')
    end

    xTarget.addMoney(amount)
end, true)

Не доверяйте id, отправленной с клиента для того, что имеет значение. Используйте source, который не может быть поддельным, как объяснено в securing server events.

4. Игрок уехал

Если игрок отключится, пока ваш код ждет, например в длинном цикле или таймере, GetPlayerFromId возвращает nil, когда он наконец запустится. Это нормальный случай, не ошибка, и ему нужна та же охрана.

Внутри playerDropped ситуация менее ясна, потому что ESX также обрабатывает это событие для сохранения и удаления игрока, и порядок обработчиков — это не то, на что полагаться. ESX Legacy также запускает свое собственное событие esx:playerDropped, но проверьте, что у вашей версии оно есть. Наиболее надежный подход — держать данные сами, пока игрок в сети:

lua
local sessions = {}

AddEventHandler('esx:playerLoaded', function(playerId, xPlayer)
    sessions[playerId] = {
        identifier = xPlayer.identifier,
        job = xPlayer.job.name,
    }
end)

AddEventHandler('playerDropped', function()
    local data = sessions[source]
    if data then
        print(('%s left, job %s'):format(data.identifier, data.job))
        sessions[source] = nil
    end
end)

Паттерн охраны

Начните каждый обработчик сервера, который использует игрока, одинаково:

lua
RegisterNetEvent('my_script:sell', function(item, count)
    local src = source
    local xPlayer = ESX.GetPlayerFromId(src)
    if not xPlayer then return end

    -- from here xPlayer is safe to use
    xPlayer.addMoney(100)
end)

Та же проверка идет внутри серверных обратных вызовов, зарегистрированных с помощью ESX.RegisterServerCallback, где первый аргумент — это источник игрока:

lua
ESX.RegisterServerCallback('my_script:getJob', function(source, cb)
    local xPlayer = ESX.GetPlayerFromId(source)
    if not xPlayer then return cb(nil) end

    cb(xPlayer.job.name)
end)

Проверьте также сторону клиента: она должна принять nil ответ от обратного вызова.

Совет: если ошибка вместо этого attempt to index a nil value (global 'ESX'), проблема в объекте ESX, а не в игроке. Смотрите ESX is nil: fixing esx:getSharedObject.

Контрольный список

Симптом Исправление
Nil сразу после присоединения игрока Ждите esx:playerLoaded вместо playerJoining
Nil после Wait Сохраните local src = source первым и используйте src
Nil из команды Преобразуйте аргумент с помощью tonumber; source равен 0 в консоли
Nil с id, отправленной клиентом Используйте source; на клиенте серверная id — это GetPlayerServerId(PlayerId())
Nil в playerDropped Держите нужные вам данные в своей таблице, пока игрок в сети
Nil для оффлайн игрока GetPlayerFromId только находит онлайн игроков; запросите базу данных
Любой nil Добавьте if not xPlayer then return end в верх обработчика

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

Почему xPlayer равна nil в ESX?

ESX.GetPlayerFromId(source) возвращает nil, когда ESX не имеет загруженного игрока для этого id. Игрок может еще не закончить загрузку, id может быть неправильным или строкой, или игрок уже уехал.

Должен ли я проверять xPlayer в каждом событии?

Да. Любое событие сервера может быть вызвано с игроком, который не загружен, поэтому начните обработчик с if not xPlayer then return end. Это ничего не стоит и предотвращает ошибку.

Могу ли я использовать xPlayer внутри playerDropped?

На это полагаться не безопасно, потому что ESX может уже удалить игрока. Держите нужные вам данные в своей таблице, пока игрок в сети, и читайте их оттуда.

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

Shop CreatorМагазин меньше чем за минуту — владельцы, сотрудники, сейфы и ограбления в комплекте.Смотреть скрипт →Pawn Shop AppЛомбард между игроками прямо в lb-phone.Смотреть скрипт →Drug Dealer AppУличная торговля в виде приложения lb-phone: зоны, NPC-покупатели, уровни и вызовы полиции.Смотреть скрипт →

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

ESXОшибкиLuaESX — это nil: исправление esx:getSharedObject в ESX Legacyattempt to index a nil value (global 'ESX')? Старое событие esx:getSharedObject исчезло из ESX Legacy. Вот однострочное исправление и что делать со скриптами, которые вы не можете редактировать.1 октября 2026 г. · 2 мин чтенияЧитать →FiveMОшибкиLuaNo such export X in resource Y: как это исправить в FiveMПолучаете ошибку 'No such export X in resource Y' в FiveM? Причины: ресурс не запущен, неправильное имя папки, несоответствие на стороне клиента или сервера, переименованный экспорт и порядок запуска.1 октября 2026 г. · 4 мин чтенияЧитать →FiveMLuaОшибкиFiveM json.decode ошибка: nil, пустая строка и исправления невалидного JSONjson.decode падает или возвращает nil в вашем FiveM скрипте? Почему декодирование nil, пустых или отредактированных вручную JSON данных ломается, что делает json.encode с смешанными ключами, и как безопасно использовать pcall.1 октября 2026 г. · 3 мин чтенияЧитать →