Engineering
Entity ownership, handles and network IDs in FiveM
How networked entities work in FiveM with OneSync: entity owners, why local handles differ between client and server, network IDs and how to convert them, requesting control, ownership migration, orphan mode, and the bugs that come from sending handles over events.
Overview
Most “it works for me but not for other players” bugs in FiveM come from one misunderstanding: an entity handle is a local number. The vehicle that is handle 131842 on your client is a different number on the server and on every other client. The shared name for an entity is its network ID, and every networked entity also has an owner — the one client that simulates it.
Handles vs network IDs
| Handle | Network ID | |
|---|---|---|
| What it is | A local reference in one script runtime | The entity’s ID across the whole session |
| Same on every machine? | No | Yes |
| Send in events? | Never | Yes |
| Get it | CreateVehicle, GetVehiclePedIsIn… | NetworkGetNetworkIdFromEntity(entity) |
local veh = GetVehiclePedIsIn(PlayerPedId(), false)
if veh ~= 0 then
TriggerServerEvent('garage:store', VehToNet(veh))
endRegisterNetEvent('garage:store', function(netId)
local src = source
if type(netId) ~= 'number' then return end
local veh = NetworkGetEntityFromNetworkId(netId)
if not DoesEntityExist(veh) then return end
local ped = GetPlayerPed(src)
if GetVehiclePedIsIn(ped, false) ~= veh then return end -- validate!
DeleteEntity(veh)
end)Converting on the client
| Direction | Natives |
|---|---|
| Entity → network ID | NetworkGetNetworkIdFromEntity, VehToNet, PedToNet, ObjToNet |
| Network ID → entity | NetworkGetEntityFromNetworkId, NetToVeh, NetToPed, NetToObj |
| Does it exist here? | NetworkDoesEntityExistWithNetworkId(netId) |
A client only knows entities near it. If the server sends a network ID for a vehicle across the map, the client cannot resolve it until it is in range — wait with NetworkDoesEntityExistWithNetworkId before converting.
local function waitForNet(netId, timeout)
local deadline = GetGameTimer() + (timeout or 5000)
while not NetworkDoesEntityExistWithNetworkId(netId) do
if GetGameTimer() > deadline then return nil end
Wait(0)
end
return NetworkGetEntityFromNetworkId(netId)
endOwners and control
With OneSync every networked entity has an owner client that runs its physics and sends its state. NetworkGetEntityOwner(entity) returns the owner — a server ID on the server, a player index on the client. Only the owner’s changes stick; when your client changes an entity it does not own, the owner overwrites it on the next update.
local function requestControl(entity, timeout)
local deadline = GetGameTimer() + (timeout or 2000)
NetworkRequestControlOfEntity(entity)
while not NetworkHasControlOfEntity(entity) do
if GetGameTimer() > deadline then return false end
Wait(0)
NetworkRequestControlOfEntity(entity)
end
return true
end
if requestControl(veh) then
SetVehicleFixed(veh)
endMigration and orphan mode
When the owner leaves the area or disconnects, ownership migrates to another nearby client. If nobody is relevant any more, the server removes the entity by default. SetEntityOrphanMode(entity, mode) on the server changes that:
| Mode | Name | Behaviour |
|---|---|---|
| 0 | DeleteWhenNotRelevant | Default — deleted when no player is relevant |
| 1 | DeleteOnOwnerDisconnect | Deleted when the original owner disconnects |
| 2 | KeepEntity | Never deleted by the server’s relevancy cleanup |
KeepEntity only stops the server deleting it; a client can still delete it. Use it for things that must survive, like a placed prop, and clean them up yourself.
Attaching data to an entity
Instead of keeping tables keyed by network ID, attach data to the entity itself with an entity state bag: Entity(veh).state:set('fuel', 62.0, true). It follows the entity everywhere. See state bags.
Frequently asked questions
Why does my entity handle not work on the server?
Handles are local to each runtime. Send the network ID (NetworkGetNetworkIdFromEntity) and convert it back on the other side.
What is an entity owner in FiveM?
The client that simulates a networked entity and sends its state. Other clients see the owner’s version.
Why do my changes to a vehicle get reverted?
You are not its owner. Request control first, or make the change with a server-side native.
Why does NetToVeh return 0?
The entity does not exist on that client yet — usually it is out of range. Wait for NetworkDoesEntityExistWithNetworkId.
How do I stop the server deleting my entity?
Call SetEntityOrphanMode(entity, 2) on the server, and delete it yourself when it is no longer needed.
Need this built, not just explained?
Ten years of FiveM work, from Lua to NUI
Custom resources, React NUI, ESX / QBCore / Qbox integration, OneSync performance audits and security reviews — plus the websites and SEO around your server brand.
Related guides
- EngineeringServer-side entity spawning in FiveMOn the server, create vehicles with CreateVehicleServerSetter(model, type, x, y, z, heading) — it is more reliable than the RPC-based CreateVehicle. Wait for DoesEntityExist, set plate and state, put the player in with SetPedIntoVehicle, and send the network ID to the client if it needs to do more. Delete with DeleteEntity. Once all scripts spawn server-side, enable sv_entityLockdown.
- EngineeringState bags in FiveM: synced data without eventsA state bag is a set of key–value pairs attached to something: GlobalState (the whole server), Player(source).state (a player) or Entity(entity).state (an entity; also LocalPlayer.state on the client). Set a value on the server and it replicates to clients that can see it; clients react with AddStateBagChangeHandler. Clients can only write their own values when the server allows it, and those writes must never be trusted.
- Getting startedClient-side vs server-side in FiveMClient scripts run on each player’s PC and handle what that player sees and does: drawing, input, markers, animations and local effects. Server scripts run once, on your server, and own everything that has value or must be trusted: money, items, jobs, the database and permissions. The client asks; the server decides. Never trust data sent by a client without checking it.
- EngineeringWriting server events that cannot be abusedAny client can call any event you registered with RegisterNetEvent, with any arguments. In each handler: copy source into a local, check argument types and ranges, re-derive everything from server state (prices, amounts, rewards), verify the player can do this now (distance, job, item, cooldown), and log refusals. Events only other server scripts should use are registered with AddEventHandler alone, so clients cannot trigger them.