Raising Errors with error()
Lua does not have try/catch; instead, the built-in error(message, level) function raises an error that immediately unwinds the call stack until something catches it. The message is usually a string but can be any Lua value (including a table, useful for structured error objects). The optional level argument controls whether position information (file:line) is prepended: level 1 (the default) points to where error() was called, level 2 points to the caller of the function that called error(), and level 0 suppresses position info entirely.
Cricket analogy: When a third umpire signals 'not out' via a instant on-field alert that halts play immediately, everything stops right there, the way error() immediately halts normal execution and unwinds the stack.
local function withdraw(balance, amount)
if amount > balance then
error("insufficient funds", 2) -- level 2: blame the caller's line
end
return balance - amount
end
local ok, result = pcall(withdraw, 100, 150)
if not ok then
print("Transaction failed: " .. result)
else
print("New balance: " .. result)
endCatching Errors with pcall
pcall(f, ...) ("protected call") invokes function f with the given arguments inside a protected environment. It always returns at least a boolean: true plus f's normal return values if f completed without error, or false plus the error value if f raised one. This is the fundamental Lua idiom for "catching" errors — instead of a try/catch block, you wrap the risky call itself in pcall and branch on its first return value.
Cricket analogy: A team sending in a night-watchman before a risky over is like wrapping a risky call in pcall, absorbing a potential dismissal without losing your best batter to the failure.
xpcall and Custom Handlers
xpcall(f, handler, ...) works like pcall but takes an additional error handler function that runs while the stack is still unwinding, before the stack is fully discarded. This matters because it lets you call debug.traceback() inside the handler to capture a full stack trace, something you cannot reconstruct after pcall has already returned and the original call stack is gone. xpcall is the standard choice when you need detailed diagnostics (e.g. logging) rather than just a pass/fail result.
Cricket analogy: A stump-mic audio review that captures the exact sound at the moment of a controversial dismissal, before the moment is lost, mirrors xpcall's handler capturing a traceback while the stack still exists.
A common pattern combines both: local ok, err = xpcall(riskyFn, debug.traceback). If riskyFn errors, err will contain the error message plus a full stack trace string, which is invaluable for logging in production servers where you can't attach a debugger.
Non-String Error Values and assert
Because error() accepts any Lua value, libraries sometimes raise a table like error({code = 404, message = "not found"}) so calling code can programmatically inspect err.code after a pcall rather than pattern-matching a string. Separately, assert(v, message) is a shorthand that raises error(message) if v is false or nil, and otherwise returns all its arguments unchanged — it's commonly used to validate function arguments or the success of an I/O operation like assert(io.open("data.txt")), which raises immediately if the file couldn't be opened.
Cricket analogy: A DRS review returning a structured verdict object (ball-tracking data, impact zone, decision) instead of just 'out' or 'not out' as plain text mirrors error() raising a structured table instead of a string.
- Lua has no try/catch;
error(message, level)raises an error that unwinds the stack until caught. pcall(f, ...)runsfprotected, returningtrue, results...on success orfalse, errorValueon failure.xpcall(f, handler, ...)adds a handler that runs before the stack unwinds, ideal for capturingdebug.traceback().error()can raise any Lua value, not just strings, enabling structured error objects with fields likecode.assert(v, message)raiseserror(message)whenvis falsy, otherwise returns its arguments unchanged.- The
levelargument toerror()controls whether position info blames the caller (2) or the error() call site (1, default).
Practice what you learned
1. What does `pcall(f, 1, 2)` return if `f` completes successfully and returns the value 42?
2. Why would you use xpcall instead of pcall?
3. What does `assert(io.open("missing.txt"))` do if the file does not exist?
4. Can error() raise a table instead of a string?
Was this page helpful?
You May Also Like
Modules and require
Learn how Lua organizes reusable code into modules with the require function, package.path, and the standard return-a-table pattern.
Coroutines in Lua
Understand Lua's cooperative multitasking primitive: creating, resuming, and yielding coroutines to write generators and non-blocking logic.
Object-Oriented Lua
Learn how Lua uses tables, functions, and metatables to build objects, methods, and encapsulation without a built-in class system.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics