Again, you don't need to define a new error type in order to allow callers to do something about it. Almost all of the time, you just need to define an exported ErrFoo variable, and return it, either directly or annotated via e.g. `fmt.Errorf("annotation: %w", ErrFoo)`. Callers can detect ErrFoo via errors.Is and behave accordingly.
`err != nil` is very common, `errors.Is(err, ErrFoo)` is relatively uncommon, and `errors.As(err, &fooError)` is extraordinarily rare.
You're speaking from a position of ignorance of the language and its conventions.
Indeed, you can absolutely handle some cases with combinations of `errors.Is` and `fmt.Errorf` instead of implementing your own error.
The main problem is that, if you recall, `errors.Is` also appeared 8 years after Go 1.0, with the consequences I've mentioned above. Most of the Go code I've seen (including big parts of the standard library) doesn't document how one could handle a specific error. Which feeds back to my original claim that "errors are primarily meant to be logged and that you have to get out of your way to develop errors that can actually be handled".
On a more personal touch, as a language designer, I'm not a big fan of taking an entirely different path depending on the kind of information I want to attach to an error. Again, I can live with it. I even understand why it's designed like this. But it irks the minimalist in me :)
> You're speaking from a position of ignorance of the language and its conventions.
This is entirely possible.
I've only released a few applications and libraries in Go, after all. None of my reviewers (or linters) have seen anything wrong with how I handled errors, so I guess so do they? Which suggests that everybody writing Go in my org is in the same position of ignorance. Which... I guess brings me back to the previous points about error-fu being considered black magic by many Go developers?
One of the general difficulties with Go is that it's actually a much more subtle language than it appears (or is marketed as). That's not a problem per se. In fact, that's one of the reasons for which I consider that the design of Go is generally intellectually pleasing. But I find a strong disconnect between two forms of minimalism: the designer's zen minimalism of Go and the bruteforce minimalism of pretty much all the Go code I've seen around, including much of the stdlib, official tutorials and of course unofficial tutorials.