Skip to content

Instantly share code, notes, and snippets.

@JonathanTurnock
Created May 30, 2025 23:42
Show Gist options
  • Save JonathanTurnock/4a552ea7d928e4dd4e815b41da782299 to your computer and use it in GitHub Desktop.
Save JonathanTurnock/4a552ea7d928e4dd4e815b41da782299 to your computer and use it in GitHub Desktop.
Error Handling in Lua: The Idiomatic Way

🛠 Error Handling in Lua: The Idiomatic Way

Lua is known for being lightweight, embeddable, and flexible—and its approach to error handling is no different. Whether you're writing a game script, a plugin, or a CLI tool, understanding how Lua handles errors is essential for writing clean, maintainable code.

In this article, we'll explore:

  • The basic mechanisms of error handling in Lua
  • When to use error() vs returning nil, err
  • Best practices for writing robust functions and libraries

🔧 The Basics: error and pcall

Lua provides two core primitives for error handling:

  • error(message) — raises a runtime error with a given message
  • pcall(func) — calls func in protected mode, returning a success flag and result

Example:

function might_fail(x)
    if x < 0 then
        error("Negative not allowed")
    end
    return x * 2
end

local ok, result = pcall(might_fail, -1)
if not ok then
    print("Caught error:", result)
end

Here, pcall safely captures the error, allowing your program to recover instead of halting execution.


🧭 Return nil, err for Expected Failures

For operations that are expected to fail under normal conditions (e.g., network requests, file I/O, database queries), the idiomatic Lua pattern is:

local res, err = some_function(...)
if not res then
    print("Failed:", err)
end

This is widely used in the standard libraries (like io.open, os.rename, etc.):

local file, err = io.open("missing.txt", "r")
if not file then
    print("Error:", err)
end

This allows calling code to decide whether and how to recover from the failure.


⚠️ Use error() for Programming Mistakes

If someone calls your function incorrectly—like passing a number instead of a string—you should not return nil, err. Instead, raise an error directly using error().

function greet(name)
    if type(name) ~= "string" then
        error("bad argument #1 to 'greet' (string expected, got " .. type(name) .. ")", 2)
    end
    print("Hello, " .. name)
end

Why? Because this is a programmer error, not a runtime failure. It should fail loudly so it’s noticed and fixed during development.

Tip: The second argument to error() (2 in the example above) adjusts the stack level so the error points to the caller, not inside your function. This results in cleaner error messages.


🤝 Combining Both in Library Code

A well-designed Lua function might use both approaches depending on the nature of the problem:

function fetch_data(url)
    if type(url) ~= "string" then
        error("bad argument #1 to 'fetch_data' (string expected)", 2)
    end

    -- Simulated network failure
    if url == "http://fail" then
        return nil, "network unreachable"
    end

    return "some data"
end

This approach is idiomatic because it distinguishes invalid use of the API (handled with error) from valid usage that fails (handled with nil, err).


✅ TL;DR Best Practices

Scenario What to do Why
Network/file/database failure return nil, err Expected, recoverable
Invalid input error("bad argument") Programming bug; fail fast
Use by library users if not res then ... Check and handle nil, err
Use in internal functions Raise with error() Catch incorrect usage early

💬 Final Thoughts

Lua’s flexibility gives you the power to choose between exception-like behavior (error()) and more traditional error returns (nil, err). But with great power comes great responsibility. Distinguishing clearly between expected operational errors and programmer mistakes is key to writing idiomatic and maintainable Lua code.

Follow this guideline, and your Lua APIs will feel clean, predictable, and Lua-like—just the way they should.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment