attempt to index a nil value (local 'Player'): QBCore and QBox fix
Player is nil in your QBCore or QBox script? Why QBCore.Functions.GetPlayer(source) returns nil, citizenid lookups for online players only, and the safe guard patterns.
In the server console:
SCRIPT ERROR: @my_script/server/main.lua:27: attempt to index a nil value (local 'Player')local Player = QBCore.Functions.GetPlayer(source)
Player.Functions.AddMoney('cash', 100) -- Player is nilGetPlayer found no loaded player for that id and returned nil, and the next line indexed it. The causes mirror the ESX case in ESX xPlayer is nil, with QBCore and QBox specifics.
1. The player is not loaded yet
A player can be connected before QBCore has loaded their character, especially while a multicharacter screen is open. Until the character is chosen, GetPlayer(source) returns nil.
Code that runs on playerJoining, or from a thread that starts immediately, hits this. Wait for the QBCore event that fires when the player is ready. On the server:
AddEventHandler('QBCore:Server:PlayerLoaded', function(Player)
print(Player.PlayerData.citizenid .. ' is loaded')
end)On the client, the matching event is QBCore:Client:OnPlayerLoaded:
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
PlayerLoaded = true
end)If your resource restarts while players are online, those events do not fire again for them. On start, go through the players who are already loaded:
CreateThread(function()
for _, src in pairs(QBCore.Functions.GetPlayers()) do
local Player = QBCore.Functions.GetPlayer(src)
if Player then
-- set up the player
end
end
end)2. source changed after a Wait
source is a global that FiveM sets for the running event. If you call Wait inside the handler, another event can run and change it.
RegisterNetEvent('my_script:sell', function()
Wait(1000)
local Player = QBCore.Functions.GetPlayer(source) -- may be wrong, or nil
end)Store it first:
RegisterNetEvent('my_script:sell', function()
local src = source
Wait(1000)
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
end)3. The id is wrong
GetPlayer expects the server id of an online player, as a number.
- A string from a command. Arguments are text, so convert them:
QBCore.Functions.GetPlayer(tonumber(args[1])). - The wrong id from the client. On the client,
PlayerId()is a local index. The server id isGetPlayerServerId(PlayerId()). Better, ignore ids sent by the client and usesource, see securing server events. - The console. A command typed in the server console has
sourceequal to0, which is not a player. - An id that has left. The player disconnected while your code waited.
QBCore.Commands.Add('givecash', 'Give cash', { { name = 'id', help = 'Player id' }, { name = 'amount', help = 'Amount' } }, true, function(source, args)
local target = QBCore.Functions.GetPlayer(tonumber(args[1]))
local amount = tonumber(args[2])
if not target or not amount then return end
target.Functions.AddMoney('cash', amount)
end, 'admin')4. citizenid lookups only find online players
Many scripts store the citizenid instead of the source, because the source changes at every session. To get the player from a citizenid:
local Player = QBCore.Functions.GetPlayerByCitizenId(citizenid)This only works while that player is online and loaded. For a player who is offline it returns nil, which is not an error in your data. Read the database for offline players:
local row = MySQL.single.await('SELECT charinfo, job FROM players WHERE citizenid = ?', { citizenid })
if row then
local charinfo = json.decode(row.charinfo)
endcharinfo is stored as JSON text, so decode it safely, see FiveM json.decode errors. Writing to an offline player is a different task: change the database row only if the player is really offline, or the next save from the server overwrites your change.
5. On QBox
QBox's core is qbx_core. It keeps a compatibility layer, so QBCore.Functions.GetPlayer still works in scripts written for QBCore. For new code, use its exports, which return the same kind of player object or nil:
local player = exports.qbx_core:GetPlayer(source)
if not player then return end
print(player.PlayerData.citizenid)For an online player by citizenid:
local player = exports.qbx_core:GetPlayerByCitizenId(citizenid)The rules from this article apply in the same way: no player until the character is loaded, store source before a Wait, and expect nil for an offline player. If you are moving a script between the cores, see converting a QBCore script to QBox.
6. playerDropped
When a player leaves, qb-core saves and removes the player on its own, and the order of handlers for playerDropped is not something to rely on. In your own playerDropped handler, GetPlayer(source) can already be nil. Keep what you need in your own table while the player is online:
local sessions = {}
AddEventHandler('QBCore:Server:PlayerLoaded', function(Player)
sessions[Player.PlayerData.source] = Player.PlayerData.citizenid
end)
AddEventHandler('playerDropped', function()
local citizenid = sessions[source]
sessions[source] = nil
if citizenid then
print(citizenid .. ' left')
end
end)The guard pattern
Start every server handler that needs a player in the same way:
RegisterNetEvent('my_script:action', function()
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
-- Player is safe to use here
end)Tip: if the error is about
QBCoreitself being nil, the problem is the core object, not the player. See attempt to index a nil value (global 'QBCore').
Checklist
| Symptom | Fix |
|---|---|
| Nil right after the player joins | Wait for QBCore:Server:PlayerLoaded instead of playerJoining |
Nil after a Wait |
Store local src = source and use src |
| Nil from a command | Convert the argument with tonumber; the console source is 0 |
GetPlayerByCitizenId returns nil |
The player is offline; query the players table |
| QBox server | Use exports.qbx_core:GetPlayer(source) and check for nil |
Nil in playerDropped |
Keep the data you need in your own table while the player is online |
| Any nil | Add if not Player then return end at the top of the handler |
Quick answers
Why does QBCore.Functions.GetPlayer return nil?
There is no loaded player with that id. The player may still be loading, the id may be wrong or lost after a Wait, or the player has already left.
Does GetPlayerByCitizenId work for offline players?
No. It only finds players who are online. For an offline player, read the players table in the database instead.
What is the QBox equivalent of QBCore.Functions.GetPlayer?
exports.qbx_core:GetPlayer(source). It returns the player object, or nil when there is no loaded player for that id.


