Errors
Errors
Section titled “Errors”Structured error handling with categorization and retry metadata. Global errors table available without require.
Creating Errors
Section titled “Creating Errors”-- Simple message (kind defaults to UNKNOWN)local err = errors.new("something went wrong")
-- With kind, retryable, and detailslocal err = errors.new({ message = "user not found", kind = errors.NOT_FOUND, retryable = false, details = {user_id = 123}})errors.new accepts either a string message or a table with at least a message field. The (kind, message) form is not supported.
Wrapping Errors
Section titled “Wrapping Errors”Add context while preserving kind, retryable, and details:
local data, err = db.query("SELECT * FROM users")if err then return nil, errors.wrap(err, "failed to load users")endError Methods
Section titled “Error Methods”| Method | Returns | Description |
|---|---|---|
err:kind() | string | Error category |
err:message() | string | Error message |
err:retryable() | boolean/nil | Whether operation can be retried |
err:details() | table/nil | Structured metadata |
err:stack() | string | Lua stack trace |
tostring(err) | string | Full representation |
Checking Kind
Section titled “Checking Kind”if errors.is(err, errors.INVALID) then -- handle invalid inputend
-- Or compare directlyif err:kind() == errors.NOT_FOUND then -- handle missing resourceendError Kinds
Section titled “Error Kinds”| Constant | Use Case |
|---|---|
errors.NOT_FOUND | Resource doesn’t exist |
errors.ALREADY_EXISTS | Resource already exists |
errors.INVALID | Bad input or arguments |
errors.PERMISSION_DENIED | Access denied |
errors.UNAVAILABLE | Service temporarily down |
errors.INTERNAL | Internal error |
errors.CANCELED | Operation was canceled |
errors.CONFLICT | Resource state conflict |
errors.TIMEOUT | Operation timed out |
errors.RATE_LIMITED | Too many requests |
errors.UNKNOWN | Unspecified error |
Call Stack
Section titled “Call Stack”Get structured call stack:
local stack = errors.call_stack(err)if stack then print("Thread:", stack.thread) for _, frame in ipairs(stack.frames) do print(frame.source .. ":" .. frame.line, frame.name) endendRetryable Errors
Section titled “Retryable Errors”| Typically Retryable | Not Retryable |
|---|---|
TIMEOUT | INVALID |
UNAVAILABLE | NOT_FOUND |
RATE_LIMITED | PERMISSION_DENIED |
ALREADY_EXISTS |
if err:retryable() then -- safe to retryendError Details
Section titled “Error Details”local err = errors.new({ message = "validation failed", kind = errors.INVALID, details = { errors = { {field = "email", message = "invalid format"}, {field = "age", message = "must be positive"} } }})
local details = err:details()for _, e in ipairs(details.errors) do print(e.field, e.message)end