Knowledge from the fieldRedM

Citizen.InvokeNative returns BOOLEAN for control/velocity natives in RedM Lua — use Lua wrappers

learning:24

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

Back to documentation