> Go has multiple returns from functions so a very typical scenario is a function that returns something and also an error, which would be nil if everything worked okay

This is one of the problems I have with C. You basically have to remember to manually check for an error on every function call, which means (1) an algorithm with short and simple pseudocode becomes lengthy and hard to read real code, because you need to add a ton of error handling, (2) it is easy to forget to handle an error in some place. Exception-based error handling lets you delegate errors to a top-level handler without cluttering up intermediate code (i.e. an exception anywhere in webpage rendering logic should be handled by 500'ing the entire page, which exception-based error handling lets you do without cluttering intermediate functions between the function producing the error and the function handling the error with error-handling logic).

I've been thinking about learning Go, but if its only error handling mechanisms are "pack it into a return value" or "panic() which is like exit(1) in C" then it's a black mark against the language. It's still a black mark if the language has exception-like error handling but it's not considered "idiomatic Go" and the stdlib and a good chunk of third-party libs report errors in return values.

Wrt error codes and (2): in Go, you have pretty much ignore errors willingly (by explicitly assigning the error to _). You cannot ignore them accidentally without compiler pestering you about ignoring the return value.

Unless the error is the only return value, in which case you can freely ignore the return-value without the compiler complaining.

Go makes it really easy to linters (lexer and parser in standard library, simple AST, etc.), so there is a robust linger for that: https://github.com/kisielk/errcheck