pcall
pcall calls a function in protected mode. If the function raises an error, pcall catches it and returns false with the error message. If the function succeeds, pcall returns true with the function’s return values.
Signature
pcall(f, arg1, arg2, ...)
Parameters:
f— the function to callarg1, arg2, ...— arguments to pass to the function
Returns: true, result1, result2, ... on success, or false, error_message on failure.
Basic Usage
Successful call:
ok, result = pcall(math.sqrt, 16)
print(ok) -- true
print(result) -- 4.0
Call that raises an error:
ok, err = pcall(math.sqrt, -1)
print(ok) -- false
print(err) -- "math.sqrt: domain error"
Why Use pcall
Without pcall, a runtime error crashes the entire script:
-- crashes the whole program
result = unauthenticated_function()
print("this never runs")
With pcall, you isolate failures:
ok, err = pcall(unauthenticated_function)
if not ok then
print("Function failed: " .. err)
-- handle gracefully, program continues
end
This is essential for user-provided code, plugin systems, API endpoints, and anywhere a failure should not terminate the host process.
Error Handling Patterns
Simple Boolean Check
ok, err = pcall(some_risky_operation)
if not ok then
log_error("Operation failed: " .. err)
end
Extracting Error Details
ok, err = pcall(function()
return some_function(arg1, arg2)
end)
if not ok then
print("Failed: " .. tostring(err))
end
Returning Error to Caller
function safe_div(a, b)
ok, result = pcall(function() return a / b end)
if not ok then
return nil, "division failed: " .. result
end
return result
end
pcall vs xpcall
pcall catches only errors raised by the function itself — it does not catch errors in finalizers or metamethods that run during garbage collection. For more reliable error handling across all contexts, use xpcall, which lets you specify a custom error handler.
-- pcall does not catch this:
ok, err = pcall(setmetatable, {}, {
__gc = function() error("finalizer error") end
})
-- ok is true (pcall itself succeeds, GC error happens later)
-- xpcall with handler:
ok, err = xpcall(function()
return some_function()
end, function(e)
return debug.traceback(e)
end)
-- err contains the full traceback
Passing Arguments
Arguments are passed after the function:
ok, result = pcall(string.format, "Hello %s", "world")
-- => true, "Hello world"
For functions with multiple return values, all are returned after the boolean:
ok, r1, r2, r3 = pcall(some_function_with_4_returns)
Common Use Cases
Safely Evaluating User Input
function safe_eval(code)
local fn, err = load(code)
if not fn then
return nil, "Syntax error: " .. err
end
return pcall(fn)
end
API Request Handling
function handle_request(request)
local ok, result = pcall(function()
return process_request(request)
end)
if not ok then
return { status = 500, error = tostring(result) }
end
return { status = 200, data = result }
end
Optional Library Loading
local ok, socket = pcall(require, "socket")
if not ok then
print("Socket library not available: " .. socket)
-- fall back to alternative
end
See Also
- /reference/core-functions/ref-print/ — output values
- /reference/core-functions/ref-tonumber/ — convert to number
- /tutorials/error-handling-basics/ — error handling patterns