unfortunately it's not so simple. that's the convention. depending on the library you're using it might be a special type of Error, or special type of Result, something needs to be transformed, `?` might not work in that case (unless you transform/map it), etc.
I like rust, but its not as clean in practice, as you describe
Your owned (i.e. not third-party) Error type is a sum type of error types that might be thrown by other libraries, with a newtype wrapper (`IOError`) on top.
Then implement the `From` trait to map errors from third-party libraries to your own custom Error space:
Errors are where I find zig severely lacking. They can't carry context. Like if you're parsing a JSON file and it fails, you can know that it failed but not where it failed within the file. Their solution in the standard library for cases like this was to handle printing to stderr internally, but that is incredibly hacky.
The std has diagnostics struct you can give to the json parser. Zig is manually memory managed language so it doesnt have payloads in errors for a good reason.
Manual memory management is not a reason Zig couldn't have supported sum types for error returns. You don't need an allocator involved at all to return a discriminated union like Rust uses.
I actually find Zig quite a pleasant language other than my gripe with not handling more complex errors as cleanly.
You would have to give up on global error set with sum types, unless you want to see the global error set bloat with the largest sum type. Also if the error payload needs allocating what are you gonna do? Allocating is no no no here. I know rust will just panic in OOM but zig chooses not to do that. Even if you allocated, since zig has no borrow checker the error handling becomes nightmare as you now have to deal with freeing the potential allocations.
Using out parameters for context, or diagnostic pattern like std does is not bad at all imo.
The only nice thing error payloads give you is better error messages in case of uncaught errors.
I like rust, but its not as clean in practice, as you describe