Lua has no try/catch; knowing pcall is essential for robust scripts and plugins.
error(msg) raises an error. The message can be any value, including a table carrying structured data. With a string, Lua prepends the position (file:line:); pass a level as the second argument to blame the caller (error(msg, 2)) or 0 to add nothing.
assert(v, msg) raises msg when v is falsy and otherwise returns all its arguments, so local f = assert(io.open(path)) is idiomatic: io.open returns nil, message on failure and assert turns that into an error.
To catch errors call the function through pcall (protected call): local ok, result = pcall(f, arg1, arg2). On success ok is true followed by f's results; on failure ok is false and the second value is the error object. xpcall(f, handler, ...) also calls a message handler before the stack unwinds, which is where you grab debug.traceback.
Two error styles coexist in Lua code:
- Return
nil, errmsgfor expected failures (file not found, bad input). The standard library does this. - Raise with
errorfor bugs and unrecoverable situations.
For cleanup, Lua 5.4 adds to-be-closed variables: local f <close> = obj calls the value's __close metamethod when the block exits, normally or by error.
Example
local function parse_age(s)
local n = tonumber(s)
if not n then error({code = "EINVAL", input = s}) end
if n < 0 then error("age must be >= 0", 2) end
return n
end
local ok, err = pcall(parse_age, "abc")
print(ok, type(err), err.code) --> false table EINVAL
ok, err = pcall(parse_age, "42")
print(ok, err) --> true 42
local f, msg = io.open("/no/such/file")
print(f, msg ~= nil) --> nil true
ok, err = xpcall(function() local t = nil; return t.x end,
function(e) return "handled: " .. e end)
print(ok, err:match("attempt to index") ~= nil) --> false trueRemember
pcall(f, ...)returnstrue, resultsorfalse, errassert(v, msg)passes values through or raises- Expected failures return
nil, msg; bugs raise witherror
Watch out for
- Calling
pcall(f(x)): that calls f outside the protection; writepcall(f, x).