Nothing is "done" until it parsed, loaded and was read end to end. Say what was verified where (parser, server log, client log, browser, game) and what was not tested.
0. Natives: look up, never guess
Before writing a native, confirm its name, parameters and side:
node scripts/natives.mjs SetEntityHeading # signature, client/server, docs link
node scripts/natives.mjs vehicle door # every native with these words
Data: the official Cfx lists (static.cfx.re/natives/natives.json and
natives_cfx.json), downloaded on first use and cached for a week in the system temp folder.
Data only, no code. Sounds, animations and model names: mri-gta-assets (gta-data.mjs).
1. Parser, natives and pitfalls
node scripts/check.mjs <resource folder> # or a list of .lua files; --no-natives offline
- Parses every
.lua(skipsnode_modules,stream,web,html,ui,dist,buildand install snippet folders like!INSTALLATION) with the bundledluaparse(Lua 5.3). CfxLua extensions are rewritten first, keeping line and column: backtick hashes,?./?[safe navigation, compound operators (+=,..=,<<=...),<const>/<close>,/* */comments, set constructors ({ .a, .b }) andlocal a, b in t. FAIL= syntax error with[line:column]. Exit code 1.WARNlines:- Native on the wrong side: a client-only native in a file that runs on the server, or
the reverse. The side comes from the manifest (
client_scripts,server_scripts); files it doesn't list go by aclient/serverfolder name; shared files are skipped. - Unknown function: a
PascalCase()call that is not a native and is not defined in the resource or in the files it imports with@resource/file.lua, with "did you mean" for a near native name. Calls guarded byif Name thenand test folders are skipped. Usually a typo, a native that never existed, or a global from another resource that isn't loaded (exportshandlers don't create globals). cond and false or x/cond and nil or x: alwaysx. Useif/else(ornot cond and x or nil).fx_versionother thancerulean. With aui_page, the NUI may lose APIs that need a secure context on CEF 144.- A single
*in the middle of a manifest path (modules/*/client.lua) matches nothing and loads nothing, silently. Usemodules/**/client.lua. - A file listed in the manifest that doesn't exist.
- Native on the wrong side: a client-only native in a file that runs on the server, or
the reverse. The side comes from the manifest (
- Prove the checker runs before trusting an all-clear: a deliberately broken file must
FAIL, a made-up native mustWARN.
2. Read the flow
Before saying it works, follow the path end to end across every resource involved: the event that triggers it, the callback, what the other side receives, the export it calls.
Lua traps the parser can't see:
- A module global with a generic name (
Zones,Points) gets overwritten: ox_lib writes globals like that when it loads its modules (lib.zones), with no error. Give module globals their own name (ShopZones). require 'config.server'(ox_lib) returns the same cached table everywhere in the resource: a field changed at runtime applies to every reader.- Event instead of polling. A loop with
Wait(0)only for drawing and controls.
3. Reload
- New file in the manifest, new
dependencyor newserver_script:refreshfirst, thenensure. Without the refresh the server loads the cached old manifest (missing files, globals nil). ensureonly the resource that changed. With themri-txadminskill:node scripts/tx.mjs refreshandnode scripts/tx.mjs ensure <res>.- Ask before restarting, with players connected:
- a resource with
stream/or modeldata_file: remounting crashes their game; - an inventory or a core (
ox_inventory,qbx_core): others hold its state; the core needs a server restart; - a resource others declare in
dependencies: they are stopped with it and don't come back by themselves (read theStopping resourcelines andensureeach one); - a resource that
provides another name (target systems): re-ensuring its dependents can start it twice on the client. Ask the player to reconnect instead.
- a resource with
- Never put a server-only resource in
dependencies: the client can't find it and FiveM drops the player ("Could not find dependency ... Killing network").
4. Logs
| Where | What it shows |
|---|---|
Server: fxserver.log in the txData profile, or the txAdmin live console |
Started resource, Couldn't start resource, server SCRIPT ERROR |
Client: FiveM.app/logs/CitizenFX_log_*.log in the FiveM install |
client SCRIPT ERROR, No such export, NUI console.log, missing dependency |
- After
ensure, the server log must show the start with no error, and the files you added must have run (a glob that matched nothing raises no error). - A clean server start proves nothing about the client: an export missing behind a
provide, for example, only fails in the player's log.
5. Bug only in game
Don't guess. Add readable logs with a prefix that is easy to filter ([SHOP] [DIAG]) at the
moment that matters, printing the state that decides the cause (task status, entity exists,
frozen, statebag value). Ask the user to reproduce, read the client log, fix the cause and
remove the temporary logs.
6. Web part
Typecheck and build the NUI, and look at it in the browser (see the mri-nui-cef skill).