Error Handling
Prerequisites: Functions
Raising errors
local function withdraw(balance, amount)
if type(amount) ~= "number" then
error("amount must be a number", 2)
end
if amount > balance then
error({code = "INSUFFICIENT", needed = amount - balance})
end
return balance - amount
end
error(message)stops the current function and unwinds the stack until something catches it.- The optional level (
2) blames the caller's line in the message, which is more useful for argument errors. - The error value can be any value — a table carries structured details.
Catching errors with pcall
local function withdraw(balance, amount)
if type(amount) ~= "number" then error("amount must be a number", 2) end
if amount > balance then error({code = "INSUFFICIENT", needed = amount - balance}) end
return balance - amount
end
print(pcall(withdraw, 100, 30))
local ok, err = pcall(withdraw, 100, "ten")
print(ok, err)
ok, err = pcall(withdraw, 100, 250)
print(ok, type(err), err.code, err.needed)
true 70
false amount must be a number
false table INSUFFICIENT 150
pcall(f, args...) ("protected call") returns true plus the results, or
false plus the error value — it never lets the error escape.
xpcall and tracebacks
local function inner() error("something broke") end
local function outer() inner() end
local ok, msg = xpcall(outer, function(err)
return "handled: " .. err
end)
print(ok, msg)
local _, trace = xpcall(outer, debug.traceback)
print(trace:match("^[^\n]+"))
false handled: main.lua:1: something broke
main.lua:1: something broke
xpcall calls a message handler while the stack is still intact —
passing debug.traceback captures the full stack trace for logging.
assert
local function parseAge(s)
local n = assert(tonumber(s), "not a number: " .. tostring(s))
return n
end
print(parseAge("36"))
print(pcall(parseAge, "abc"))
36
false main.lua:2: not a number: abc
assert(value, message) returns value if it's truthy, and raises the
message otherwise. It pairs well with functions that return
nil, "error message":
local f, err = io.open("missing.txt")
print(f, err)
print(pcall(function() return assert(io.open("missing.txt")) end))
nil missing.txt: No such file or directory
false main.lua:3: missing.txt: No such file or directory
Two error styles
- Return
nil, messagefor expected failures the caller should handle (a missing file, invalid input). The standard library uses this style. - Raise with
errorfor programming mistakes and truly exceptional situations.