Most of blame for the mess is that the error interface throws away meaningful information. Then the caller is left mentally checking how to handle the error. Do I value check? Type cast? String check? Does the library expose a function to check, or do I do it myself? Can I get stack traces in some cases without introducing a production cost?
I'm not sure if Go needs a different type of error interface (ie diff methods), or if it needs Generics to solve this properly in my view. But, I just know I've hated the experience.
After I switched to Rust it all felt so familiar, and yet so different. I believe Rust and Go share error patterns. Yet in Rust I'm never left wondering what an error is, what I should do with it, how I check for specific types. This is largely due to awesome enum support and of course generics. Does Go need this feature set to "fix" my complaints with errors? Probably not.. but I do think it needs something.
Though I will agree, I don't think the `if err != nil` is fundamentally the problem with Go's errors, at all. Sure, the UX could be improved, but that's another story all together imo.