Citizen.InvokeNative returns BOOLEAN for control/velocity natives in RedM Lua — use Lua wrappers
Context
Calling natives that return float or Vector3 via Citizen.InvokeNative(0x...) in a RedM Lua resource. Specifically: GET_CONTROL_NORMAL, IS_CONTROL_PRESSED, IS_DISABLED_CONTROL_PRESSED, GET_ENTITY_VELOCITY.
The trap
Even though the docs list the return type as float / BOOL / Vector3, calling them through Citizen.InvokeNative(hash, ...) returns a boolean in RedM's Lua runtime. Code like:
local moveUD = Citizen.InvokeNative(0xEC3C9B8D5327B563, 0, 0xFDA83190) -- GetControlNormal
if math.abs(moveUD) > 0.05 then -- ERROR: bad argument #1 to 'abs' (number expected, got boolean)
local vel = Citizen.InvokeNative(0x4805D2B1D8CF94A9, ped) -- GetEntityVelocity
print(vel.x) -- ERROR: attempt to index a boolean value
The fix
Use the Lua wrapper (the Lua (Direct) form in the native docs) for these:
local moveUD = GetControlNormal(0, 0xFDA83190)
local pressed = IsControlPressed(0, 0x8FFC75D6)
local vel = GetEntityVelocity(ped) -- returns vec3 with .x .y .z
The wrappers handle the return-type marshalling correctly.
Pattern
This appears to affect natives whose return type isn't a plain int/handle — float, BOOL, and Vector3 returns from InvokeNative come back as boolean. A related case is documented for GetPedBoneCoords (vec3 returns drop y/z via InvokeNative).
Rule of thumb: for natives returning float, BOOL, or Vector3, prefer the Lua wrapper. Citizen.InvokeNative is fine for void returns and integer-handle returns (entity / ped / weapon hashes).
Linked natives
GET_CONTROL_NORMAL(0xEC3C9B8D5327B563)GET_ENTITY_VELOCITY(0x4805D2B1D8CF94A9)
Tags: lua, invokenative, controls, velocity, gotcha, return-types
Category: natives
Source: ch-superman
Created: 2026-05-03T12:33:08.126Z