> any code search reveals that "if err != nil { return err }" is everywhere
Code searches in languages with exceptions tend to wrap the tryblocks around massive portions of code instead of the individual function calls to the point that you have a top level doing:
But that is exactly how error handling usually works, especially if cleanup is handled separately - you just need to propagate the errors, usually all the way up to the user, who is the only one who can take a meaningful decision.
Almost all actual error handling in code is either error translation and re-throw, resource cleanup, or automatic retries (sometimes you retry the same request, sometimes you try a fallback option, but it's still the same idea).
The user however may be able to check and actually fix their internet connection, they may fix the typo they did in the config file, they may call support to see what's happening to the database etc. - your program can't do any of these things.
That's why exceptions work so well in most languages, especially GC languages where you have dramatically fewer resources to cleanup: they bubble up automatically towards the initial caller, which is often the user. Threading messes with this, but if you use the more modern async style (async/await in most languages) you get proper exception propagation even then.
On the opposite end of the spectrum, yes, as they pointed out you can just return all of the err's up the stack.
I wasn't saying that Go's approach solves this, just that it's not a problem unique to Go.
And in the case of Go it's painfully obvious that you're ignoring all of those errors whereas in other languages you can't always tell, visually, that they're being ignored because of the magic of exceptions.
Code searches in languages with exceptions tend to wrap the tryblocks around massive portions of code instead of the individual function calls to the point that you have a top level doing: