This explains it (tl;dr nobody bothers to formally define what errors they return, and the blindly propagate such unspecified errors, and it leads to ambiguity and unintentional program behavior)
https://www.lainchan.org/%CE%BB/src/1612397614615.jpg
- wrapping every underlying error in your own error type is not helpful
- but defining every underlying error in your own type confuses your implementation (and especially dependencies) with your interface
- and most errors can't be handled in code anyway
There are a few errors (mostly in file operations) that are individually handled as normal parts of life, but otherwise they really are just there to send back up to the user. It's more important to know where an error can happen than what it is.
Other than that, I can't think of any way the error handling subtly introduces bugs.
The mistake of the programmer missing an error that should be handled in a particular situation could be considered a subtle bug, I suppose. This is different to languages that have compiler-enforced error handling, where if you forget to handle a certain case the code won't compile.
(The only language I know where this is nominally "solved" is Java if you confine yourself to its checked exceptions, but nobody considers that solution "satisfactory", and indeed can be taken as a rough-and-ready proof that there may not even be a "static" solution to this problem that is usable. I'm beginning to think of it as "Errors don't compose, because they contain every possible pathology that would prevent values from composing." At this point, based on the consistent failures trying to create composable error solutions despite substantial effort poured into it across multiple languages, I am going to operate under the assumption there is no such solution until someone produces one.)
If you index into a map, then you get a tuple (val, err), where `err` is non nil if the value exists, and `val` is the value in the map or "the default construction of the value".
Go also silently discards tuple members - e.g. `v = map[4]` is valid, and silently discards the error.
This kind of means that all go maps can accidentally be defaultdicts (in Python terminology), but it's also an excellent way to introduce bugs without meaning to.