Exit, Pursued by an Error: Simpler Error Handling in Go using gobail
Pascal Dennerly
Software Engineer at Capital One | Java | Go | AWS | Cloud | DevOps | DM to say hello
Error handling in Go can sometimes feel repetitive. You check if there's an error, add context, and pass it up the chain—over and over again.
But what if, in some cases, you didn't have to?
Sometimes, the right call is to exit your program entirely. Maybe the error is critical, or there's simply no useful next step. In these moments, having a clean, simple way to exit can actually reduce complexity in your code.
I recently explored how to do this in a way that's easy to read, easy to test, and maintainable. The result? gobail, a Go library that makes it simple to exit cleanly on error—without repetitive conditionals.
Why Exit at All?
Exiting might feel like a last resort, but sometimes it's the right choice. It makes sense if:
If one of these conditions applies, exiting early can simplify your code.
The Classic Way to Exit in Go
Here’s the familiar approach:
err := myFunc()
if err != nil {
fmt.Printf("doing my thing: %v", err)
os.Exit(1)
}
This works fine for small cases, but it has limitations:
To make it more testable, you might inject a custom exit function, like this:
var customExit = os.Exit
func myFunc() {
err := someOtherFunc()
if err != nil {
fmt.Printf("doing my thing: %v", err)
customExit(1)
}
}
This works, but there’s still repetition. Can we make it even simpler?
A Cleaner Approach with gobail
With gobail, you no longer need to repeat the error-checking logic. Here’s the same example, rewritten:
func myFunc() {
gobail.Run(someOtherFunc()).OrExitMsg("with message")
}
No more if statements. No repeated calls to os.Exit. Just clean, readable code.
Handling Single and Multi-Value Returns
Many functions in Go return just an error, but plenty return (value, error) pairs as well. gobail supports both.
gobail.Return(someFuncThatReturnsError()).OrExitMsg("something went wrong: %v")
gobail.Return2(returnValueAndError()).OrExitMsg("something went wrong: %v")
In both cases, you avoid if statements and gain the option to include context about the error directly in the exit message.
Exiting Isn’t the Only Option
Sometimes, you might not want to exit the program—you may want it to panic instead. gobail can handle that too.
gobail.Run(someFunc()).OrPanicMsg("unexpected failure: %v")
This is useful for cases where you want stack traces to diagnose what went wrong. With gobail, you have the flexibility to exit or panic, depending on your needs.
Why Use gobail?
By removing repetitive error-checking logic, your functions become simpler and more readable. Instead of wrapping every function call in an if block, you can assume that errors will be handled properly.
When it comes to testing, you don't have to mock out os.Exit or test every possible exit path. Instead, gobail provides coverage for this logic, and linters will highlight any unhandled errors in your code—prompting you to decide if gobail is a good fit for those cases.
Finally, since gobail is fully tested, you can be confident that its behavior is well-defined and safe to use in production.
Try It Out
If you'd like to see how it works, check out gobail on GitHub. It's simple to use, well-tested, and actively maintained.
I’d love to hear your thoughts. Have you used similar techniques in your projects? Do you have ideas for how to improve it? Drop a comment or raise an issue or PR on the repo.