Skip to main content
Lua fundamentals

Written lessons and reference material are currently in English.

On this page

Debug class for total beginners

This is the early primer shown before your first line of Lua on the scripts-from-zero path. Use it now for the error-reading habit, then revisit it later when exports, SQL, and framework errors become real in your own server. An error is a clue, not a verdict: Lua tried one specific thing, and one specific part was missing. You will build a tiny resource named qu_debug_class, break it on purpose, read the real error, and fix it with print(type(value), value).

You'll build
A calm way to read errors before you start changing random code.
Time
~18 minutes
You need
No setup to read. The hands-on exercise needs a running test server and txAdmin console access.
You'll learn
Read the first error -> spot nil -> spot wrong-side calls -> spot broken exports -> debug in a clean order
BEFORE YOU START

Watch: debugging in action

Watch a real debugging pass first, reading the error, finding the line, and fixing one thing, then do the hands-on build below.

Reading errors and fixing scripts, step by step.

Build it

Make the resource folder

The server has one folder for this lesson.

Inside your server's resources folder - the resources folder lives in your FXServer data/base folder, the same place that contains your server.cfg - create this folder:

text
resources/qu_debug_class

Create the files

Every file named in the manifest exists.

Create this exact file layout:

text
resources/qu_debug_class/
fxmanifest.lua
server.lua

Write fxmanifest.lua

FiveM knows which files to load.

Open fxmanifest.lua and paste this. Lua 5.4 is the only runtime in 2026, so there is no lua54 line to add. Leave it out.

lua
fx_version 'cerulean'
game 'gta5'
 
server_script 'server.lua'

Break it on purpose

The resource contains one known nil bug.

Open server.lua and paste this on your test server. The variable player is nil because nothing ever filled it, so reading player.name will produce a nil error when you run the command.

lua
RegisterCommand('debugclass', function()
local player = nil
print('[qu_debug_class] name is ' .. player.name)
end, true) -- final `true` = restricted: only principals with ACE permission (e.g. the server console / admins) may run it, so a normal player cannot trigger this command

Start it and trigger the error

The exact nil error appears in the console.

Open server.cfg and add this line:

text
ensure qu_debug_class

Save. Open your server's txAdmin address, log in, and open the Live Console. The default http://localhost:40120 works when your browser is on the same machine as txAdmin; a remote VPS needs your configured administrator connection. Run these commands there, one at a time:

text
refresh
ensure qu_debug_class

refresh discovers the new resource and its manifest. ensure starts it, or restarts it if it is already running. Adding a line to server.cfg does not execute that line in a running server. Confirm there is no startup error before continuing. Now run the command:

text
debugclass

You will see a SCRIPT ERROR. Read only the first red line. It names the file (server.lua), the line number (3), and the missing thing (player).

Translate the error into plain English

You know which of the four nil errors you have.

nil means "there is nothing here." It becomes an error only when you use the nothing like it was real data or a real function. There are four you will meet constantly:

text
attempt to index a nil value         -> you read thing.name on an empty thing
attempt to call a nil value          -> you ran thing() but thing is not a function
attempt to concatenate a nil value   -> you glued text onto an empty value
attempt to perform arithmetic on nil -> you did math (+ - * /) on an empty value

Yours says index a nil value (local 'player'). So stop asking "why is Lua broken?" and ask "what value did I assume existed here?" The answer is player.

Confirm it with the fastest debug tool

The console proves player is nil before you change anything.

Add print(type(player), player) immediately before the failing access. Keep the original access in place so you can see the diagnostic output followed by the same failure. Edit server.lua to this:

lua
RegisterCommand('debugclass', function()
local player = nil
print('[qu_debug_class] type check', type(player), player)
print('[qu_debug_class] name is ' .. player.name)
end, true)

Then restart qu_debug_class and run debugclass again.

Fix the one thing and test again

The command prints a real name and no error.

The fix is to give player a real table with a name key, instead of nil. Change server.lua to this and restart cleanly:

lua
RegisterCommand('debugclass', function()
local player = { name = 'Los Santos' }
print('[qu_debug_class] type check', type(player), player)
print('[qu_debug_class] name is ' .. player.name)
end, true)

Run restart qu_debug_class, then debugclass. No red line, and the name prints. You read the first error, found the file and line, named the missing value, proved it, and fixed exactly one thing.

If something went wrong

SymptomFix
Resource qu_debug_class does not existCheck the folder is in the active server's resources directory and contains fxmanifest.lua. Run refresh, then ensure qu_debug_class. Keep the spelling identical; restart alone does not discover a new folder.
Could not load resource qu_debug_classOpen fxmanifest.lua and fix the first quote, brace, or file name error the console reports. Do not add a lua54 line; it is deprecated and ignored.
Failed to load script / unexpected symbol near '<eof>'A syntax error: a missing end, quote, or bracket. Open the file and line the console names and balance the quotes, parentheses, and ends.
attempt to call a nil value (global 'GetPlayerEndpoint')That function is server-only. Check the named file's client_script, server_script or shared_script entry in fxmanifest.lua. The manifest determines where it runs; a filename alone does not.
No such export in resource qb-core or ox_inventoryCheck the resource name, startup status, export spelling, client/server side and the installed version's documented API. A started resource can still lack the export you called.
The command prints nothing in F8This resource is a server_script. Because you triggered the command from the txAdmin Live Console, its output appears there, not in F8. (If you ever trigger a server command from in-game, FiveM may also mirror server output to your F8 console - but the server console is always the reliable place to read it.)

What you can do now

  • Read the first red error line and translate it into plain English before touching code.
  • Tell the four nil errors apart: index, call, concatenate, and arithmetic.
  • Use print(type(value), value) on the line before the crash to prove what is nil.
  • Use the error's file path and the manifest to check whether the code runs on the client or server.
  • Check resource startup, spelling, client/server side and API compatibility when an export is missing.

Try it yourself

Use the same method on your next error

Paste a sanitized first error into the free error decoder for a suggested investigation path, then check the named file and line yourself. It interprets text; it does not inspect your running server or prove that a proposed fix works. Record the command or player action, expected result, actual error and the single change you tested. Remove player identifiers, keys and connection strings before sharing an excerpt.

When you finish this exercise, run stop qu_debug_class and remove its ensure line from your test configuration if you do not need it to start again. Keep the two source files for practice.

Ready for the next step?

Tried the exercise? Mark this lesson complete when you feel ready.

Your checkmarks are saved in this browser.

Bring your AI assistant along

Copy the lesson and its technical context to ask your own assistant for help.