I think you are on to something. As I've said, the boilerplate is ugly, but manageable. It is the process of using and reporting errors that is the problem.
If the error interface were expanded, to included methods like
int Type()
int SubType()
[]Stack StackTrace()
error Cause()
Log(w Writer,string format,...)
with stdlib defining constants for errors, and user developed constants > N, the chances of constant collision is minimal.
Alternatively, define like this
string Type()
string SubType()
with the Type being package.SomeErrorName
and sub-type being package.SomeErrorName.SubErrorName
to allow easier capture and retry.
To go even further, add a
bool Permanent()
to signify if the same call is made with the same parameters, it is also fail - unless some action is taken (network reconfig, etc.) This is a more difficult implementation, but could be just a 'hint'.
It's is some amount of work to define the constants, and change existing code, but it is just busy work. The Go error handling is worse than C in that at least in C, the api doc clearly spells out which error codes can be returned, and why. With the Go error interface, and the 'minimal api doc', what is returned when is anybody's guess.