Actions and client input
fail, isActionOk, replyError and the strict readers readInt, readFinite, readId, readText, readVec3, readVec4, oneArg, asArgs, isRecord.
Everything a client sends can be faked by a cheater: a negative amount, a fraction where you expect a whole number, a 10 MB string, an object instead of a number. The strict readers on this page turn one raw value into a checked value, or null to refuse it. They never replace a bad value with a default (that is what the panel data readers do, for files the server owner edits).
Every server action answers an ActionResult: { ok: true } or a refusal with a lang key.
import { fail, isActionOk, replyError, readInt, readFinite, readId, readText, readVec3, readVec4, oneArg, asArgs, isRecord } from "@aicore-fivem/lib/shared";Where the readers go: the args option of onClientCallback and onClientEvent (see Client input). The parser gets the raw arguments as an array and returns the checked ones as an array, or null to refuse the call before your handler runs.
Action results
fail
Builds a refusal: { ok: false, error }. Return it from an action handler; the client's callAction shows the translated text of error as an error notification.
Side: Client, server and NUI · Waits: no
fail(error: string): { ok: false; error: string }return aiLib.fail('NOT_ENOUGH_MONEY') -- { ok = false, error = 'NOT_ENOUGH_MONEY' }Parameters
Prop
Type
Returns
{ ok: false, error: string }, which fits any ActionResult.
Example
import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";
import { fail, oneArg, readInt, type ActionResult } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
onClientCallback(
"my-shop:buyWater",
{ args: oneArg((v) => readInt(v, 1, 10)), lock: true },
(source, count): ActionResult => {
if (!core.CanCarryItem(source, "water", count)) return fail("NO_SPACE");
if (!core.RemoveMoney(source, "cash", count * 5, "Water")) return fail("NOT_ENOUGH_MONEY");
core.AddItem(source, "water", count);
return { ok: true };
},
);On the client, callAction("my-shop:buyWater", [2], { fallback: "BUY_FAILED" }) (Lua aiLib.callAction) shows the refusal for you. See Talking to the server.
isActionOk
Checks whether a reply is a successful ActionResult (ok === true). Use it when you read a reply by hand instead of with callAction.
Side: Client, server and NUI · Waits: no
isActionOk(reply: unknown): reply is { ok: true } & Record<string, unknown>Lua: no twin; check type(reply) == 'table' and reply.ok == true.
Parameters
Prop
Type
Returns
true when reply is an object with ok: true. The extra fields are not checked: parse the ones you read.
Example
import { triggerServerCallback } from "@aicore-fivem/lib/client";
import { isActionOk, readId } from "@aicore-fivem/lib/shared";
/** Asks the server to create a garage; answers its new id, or null. */
async function createGarage(name: string): Promise<number | null> {
const reply = await triggerServerCallback("my-garage:create", [name]).catch(() => null);
if (!isActionOk(reply)) return null;
return readId(reply.id); // an extra field: check it like any other input
}replyError
The lang key of a refused reply: its error, or fallback when the reply is missing or malformed. null when the reply is ok.
Side: Client, server and NUI · Waits: no
replyError(reply: unknown, fallback: string): string | nullLua: no twin.
Parameters
Prop
Type
Returns
null for an ok reply. Otherwise the reply's error when it is a non-empty string, else fallback.
Example
import { triggerServerCallback, notify, loadLocaleTexts } from "@aicore-fivem/lib/client";
import { replyError } from "@aicore-fivem/lib/shared";
const texts = loadLocaleTexts();
async function buyWater(): Promise<boolean> {
const reply = await triggerServerCallback("my-shop:buy", ["water"]).catch(() => null);
const error = replyError(reply, "BUY_FAILED");
if (error !== null) notify(texts[error] ?? error, "error");
return error === null;
}Strict readers
readFinite
A finite number, else null. NaN, Infinity, text and everything else are refused.
Side: Client, server and NUI · Waits: no
readFinite(value: unknown): number | nullLua: no twin; check type(value) == 'number' and value == value and value ~= math.huge and value ~= -math.huge.
Parameters
Prop
Type
Returns
The number, or null.
Example
import { readFinite } from "@aicore-fivem/lib/shared";
readFinite(12.5); // 12.5
readFinite(NaN); // null
readFinite("12"); // nullreadInt
A whole number between min and max (both included), else null. Fractions, NaN, Infinity, text and values out of range are refused. Use it for counts, amounts, slots, indexes.
Side: Client, server and NUI · Waits: no
readInt(value: unknown, min: number, max: number): number | nullLua: no twin; check math.type(value) == 'integer' and value >= min and value <= max.
Parameters
Prop
Type
Returns
The number, or null.
Example
import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";
import { fail, readInt, readText } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
const prices = new Map<string, number>([["water", 5], ["bread", 3]]);
onClientCallback(
"my-shop:buy",
{
args: ([rawItem, rawCount]) => {
const item = readText(rawItem, 64);
const count = readInt(rawCount, 1, 50);
return item !== null && count !== null ? [item, count] : null;
},
lock: true,
},
(source, item, count) => {
const price = prices.get(item); // only items this shop sells
if (price === undefined) return fail("UNKNOWN_ITEM");
if (!core.CanCarryItem(source, item, count)) return fail("NO_SPACE");
if (!core.RemoveMoney(source, "cash", price * count, "Shop")) return fail("NOT_ENOUGH_MONEY");
core.AddItem(source, item, count);
return { ok: true };
},
);readId
A positive 32-bit whole number (1 to 2,147,483,647), else null. Use it for record ids, tokens and network ids a client sends.
Side: Client, server and NUI · Waits: no
readId(value: unknown): number | nullLua: no twin; check math.type(value) == 'integer' and value > 0 and value <= 2147483647.
Parameters
Prop
Type
Returns
The id, or null.
Example
import { onClientCallback, vehicleFromNet } from "@aicore-fivem/lib/server";
import { oneArg, readId, fail } from "@aicore-fivem/lib/shared";
onClientCallback("my-tow:attach", { args: oneArg(readId) }, (source, netId) => {
const vehicle = vehicleFromNet(netId);
if (vehicle === 0) return fail("NO_VEHICLE");
return { ok: true };
});A valid id is not a valid target. Always check that the record or entity exists, that the player may use it, and that they are near it.
readText
A trimmed, non-empty string cut to max characters, else null. Use it for names, item names, notes, search text.
Side: Client, server and NUI · Waits: no
readText(value: unknown, max: number): string | nullLua: no twin; check type(value) == 'string', then trim and cut it (value:sub(1, max)).
Parameters
Prop
Type
Returns
The trimmed text (at most max characters), or null when it is not a string or is empty after trimming.
Example
import { readText } from "@aicore-fivem/lib/shared";
readText(" Hello ", 64); // "Hello"
readText(" ", 64); // null
readText(42, 64); // nullreadVec3
A point from client or export input, every coordinate finite, else null. Accepts an object { x, y, z } and a Lua vector, which reaches TypeScript as an array [x, y, z].
Side: Client, server and NUI · Waits: no
readVec3(value: unknown): { x: number; y: number; z: number } | nullLua: no twin; Lua code reads value.x, value.y, value.z (works for vectors and tables).
Parameters
Prop
Type
Returns
A new Vec3 object, or null.
Example
import { registerExport } from "@aicore-fivem/lib/server";
import { readVec3, type Vec3 } from "@aicore-fivem/lib/shared";
const markers: Vec3[] = [];
// Works for exports["my-markers"].AddMarker(vector3(1, 2, 3)) from Lua and AddMarker({ x: 1, y: 2, z: 3 }) from TypeScript.
registerExport("AddMarker", (raw: unknown) => {
const point = readVec3(raw);
if (!point) return false;
markers.push(point);
return true;
});readVec4
A point with a heading, else null. Accepts { x, y, z, heading }, { x, y, z, w } and a Lua vector4 ([x, y, z, w]). A missing heading reads 0.
Side: Client, server and NUI · Waits: no
readVec4(value: unknown): { x: number; y: number; z: number; heading: number } | nullLua: no twin.
Parameters
Prop
Type
Returns
A new Vec4 object (heading 0 when none was given), or null when a coordinate or the given heading is not a finite number.
Example
import { readVec4 } from "@aicore-fivem/lib/shared";
readVec4({ x: 1, y: 2, z: 3, w: 90 }); // { x: 1, y: 2, z: 3, heading: 90 }
readVec4([1, 2, 3]); // { x: 1, y: 2, z: 3, heading: 0 }
readVec4({ x: 1, y: 2 }); // nulloneArg
Turns a reader into an args parser for a callback or event that takes exactly one value: { args: oneArg(readId) }.
Side: Client, server and NUI · Waits: no
oneArg<T>(read: (value: unknown) => T | null): (args: unknown[]) => [T] | nullLua: no twin.
Parameters
Prop
Type
Returns
A parser that returns [value], or null (refuses the call) when read returned null.
Example
import { onClientCallback } from "@aicore-fivem/lib/server";
import { oneArg, readText } from "@aicore-fivem/lib/shared";
const notes = new Map<number, string>();
onClientCallback("my-notes:save", { args: oneArg((v) => readText(v, 500)) }, (source, text) => {
notes.set(source, text);
return { ok: true };
});asArgs
Wraps one already parsed value as an args result: [value], or null when the value is null. Use it when your own check function returns the value or null.
Side: Client, server and NUI · Waits: no
asArgs<T>(value: T | null): [T] | nullLua: no twin.
Parameters
Prop
Type
Returns
[value], or null.
Example
import { onClientCallback } from "@aicore-fivem/lib/server";
import { asArgs, toVehicleSetup, type VehicleSetup } from "@aicore-fivem/lib/shared";
const previews = new Map<number, VehicleSetup>();
onClientCallback("my-shop:preview", { args: ([raw]) => asArgs(toVehicleSetup(raw)) }, (source, setup) => {
previews.set(source, setup);
return { ok: true };
});isRecord
Checks that a value is a plain object (not null, not an array).
Side: Client, server and NUI · Waits: no
isRecord(value: unknown): value is Record<string, unknown>Lua: no twin; check type(value) == 'table'.
Parameters
Prop
Type
Returns
true for an object like { a: 1 }. false for null, arrays, numbers, strings.
Example
import { isRecord, readText } from "@aicore-fivem/lib/shared";
function readNote(raw: unknown): { title: string } | null {
if (!isRecord(raw)) return null;
const title = readText(raw.title, 80);
return title === null ? null : { title };
}