Hi everyone!
I've been working on a library called fallo (failure in my native language) for quite a while now, and I realized I never actually shared it with the community until now. You know that classic "it's not ready yet" syndrome? Well, here we are!
If you've ever felt that Lua's pcall/error pattern gets messy in complex Neovim plugins, or you've written too many if err ~= nil then ... end chains, this might be exactly what you're looking for.
What's fallo?
Fallo is a modern, ergonomic error handling library for Lua, heavily inspired by Rust's Result type. Instead of throwing errors or returning nil, err pairs, you get explicit Ok and Err variants with immutability that you can chain, transform, and propagate cleanly. The whole idea is to make error handling in Lua less painful and way more readable (I hate Go's error handling pattern, if you haven't noticed it yet).
Why you might want to use it
- Error propagation: This is the big one. Tired of checking every single function call? With fallo, you can use
:unwrap()to bail out early, or:try()to propagate errors up the call stack without all the boilerplate. Makes deeply nested operations actually readable. - Seamless Lua interop: It doesn't force you to rewrite everything. You can wrap existing functions that throw errors and convert them to
Resulttypes. You can also go the other way around and convert Results back to Lua's error system. It plays nicely with the existing ecosystem. - Structured errors: No more strings all the way down. You can carry metadata, context, and even stack traces! And since fallo uses LuaCATS annotations, you get proper type inference in Neovim with LSP support, so you know exactly what you're dealing with at each step.
- Method chaining: Write fluent, readable code (example not specifically tailored to Neovim, since the library is meant to be used anywhere):
​
-- Old way:
local file = io.open("config.json")
if not file then return nil, "Could not open file" end
local content = file:read("*a")
local ok, parsed = pcall(json.decode, content)
if not ok then return nil, "Invalid JSON" end
-- ... now validate it, handle more errors ...
-- With fallo:
read_config()
:map(parse_json)
:and_then(validate)
:inspect(function(cfg) print("Config loaded:", cfg.name) end)
:unwrap_or_else(function(err) return default_config end)
- Zero dependencies: It's a self-contained single file. Drop it in your project,
git cloneit or install it through LuaRocks and you're good to go.
Why I'm sharing this now
The library is stable and battle-tested with a solid test suite right now, but I'm looking for early adopters to help with real-world dogfooding. I want to see how it actually performs in Neovim plugins, get feedback on the API, and understand what the plugin developer ecosystem needs for better error handling since I've been out of Neovim plugins development for quite a while now.
If this resonates with you, please try it out! There's a growing set of examples to get you started, and it's available on LuaRocks:
$ luarocks install fallo
Or just grab the single file from the repo if you prefer.
I'd genuinely love to hear your thoughts. What works, what doesn't, what's missing. That's how we make the ecosystem better for everyone!
Repository: https://github.com/NTBBloodbath/fallo