Zig Error Patterns

70 Bogdanp 11 8/6/2025, 3:03:19 PM glfmn.io ↗

Comments (11)

vrnvu · 1h ago
It's amazing how coherent Zig's fundamental building blocks are as a programming language, everything fits together like a puzzle.

This post reminds me of one of Andrew's early talks about the type system and the comptime... With the core building blocks, we can achieve elegant solutions without adding unnecessary syntax complexity.

davidkunz · 49m ago
A little bit unrelated, but how do people deal with the abstinence of payloads in zig errors? For example, when parsing a JSON string, the error `UnexpectedToken` is not very helpful. Are libraries typically designed to accept an optional input to store potential errors?
hansvm · 39s ago
At a practical level, most of the language doesn't care about the distinction between errors and other types. You mostly just have to consider `try/catch/errdefer`. Your question then, mildly restated, is "how do people deal with cases where they want to use `try/catch/errdefer` but also want to return a payload?"

It's worth asking, at least a little, how often you want that in the first place.

Contrasting with Rust as an example, suppose you want Zig's "try" functionality with arbitrary payloads. Both functions need a compatible error type (a notable source of minor refactors bubbling into whole-project changes), or else you can accept a little more boilerplate and box everything with a library like `anyhow`. That's _fine_, but does it help you solve real problems? Opinions vary, but I think it mostly makes your life harder. You have stack unwinding available if you really need to see the source of a thing, and since the whole point of `try` is to bubble things up to callers who don't have the appropriate context to handle them, they likely don't really care about the metadata you're tacking on.

Suppose you want Zig's "catch" functionality with arbitrary payloads. That's just a `union` type. If you actually expect callers to inspect and care about the details of each possible return branch, you should provide a return type allowing them to do stuff with that information.

The odd duck out is `errdefer`. IMO it's reasonably common for libraries to want to do some sort of cleanup on "error" conditions, where that cleanup often doesn't depend on which error you hit, and you lose that functionality if you just return a union type. My usual workaround (in the few cases where I actually want that information returned and also have to do some sort of cleanup) is to have a private inner function and a public outer function. The inner function has some sort of `out` parameter where it sticks that unioned metadata. The outer function executes the code which might have to be cleaned up on errors, calls the inner function, and figures out what to do from there. Result location semantics make it as efficient as hand-rolled code for release builds. Not everything fits into that paradigm, but the exceptions are rare enough that the extra boilerplate really isn't bad on average (especially when comparing to an already very verbose language).

maleldil · 19m ago
> Are libraries typically designed to accept an optional input to store potential errors?

Yes. Stdlib's JSON module has a separate diagnostics object [1]. IMO, this is the weakest part of Zig's error handling story, although the reasons for this are understandable.

[1] https://ziglang.org/documentation/master/std/#std.json.Scann...

etyp · 1h ago
This goes to show how Zig's language design makes everything look nicer and simpler - the `errdefer` patterns in tests are super nice! I've debugged my Zig tests with simple print debugging (or try to narrow it down to a standalone case I can use a debugger), but I'll certainly use some of these tricks in the future.
rkagerer · 39m ago
I love the formatting and coloring on this blog page, it's delightful to read. Like an old school DOS game.
ijustlovemath · 2h ago
The website design is so pleasing, props!
yahoozoo · 9m ago
Cool stuff, but the mixed casings I see here (and have in other Zig code) puts me on edge (not literally but yeah). You’ve got `addSystemCommand` then a variable named `debug_step` which has a call `dependOn`. That said, looks like most of the stdlib stuff is camel case so the snake case variables are just the authors preference.
skrebbel · 1h ago
Wow, errdefer sounds like the kind of thing every language ought to have.
ww520 · 1h ago
These are excellent tips. I especially like the debugger integration in build.zig. I used to grep the cache directory to find the exe. The integration avoids all the extra steps.
jiehong · 1h ago
Nice Font! (Berkeley Mono)