The programmer needs to be aware that they will need to provide enough context in case of a failure. One thing I see a lot in Go examples is this pattern:
body, err := readFile(fileName)
if err != nil {
return "", err
}
If the error returned by readFile is just "not found", it would indeed be very vague. This is still poor error handling, in my opinion, since a lot of the context is lost. Yes, they are "handling" the error, but only enough to stop the linter from complaining. I prefer something like this:
body, err := readFile(fileName)
if err != nil {
return "", errors.Wrapf(err, "readFile(%s)", fileName)
}
This would result inan error like this:
readFile(file.txt): not found
This way I get all the context I need to know where the error happened and the arguments that caused the error.
If the error happened not because of a function call, but, say, an invalid value, instead of this:
if n < 10 {
return fmt.Error("invalid argument")
}
Do this:
if n < 10 {
return fmt.Errorf("invalid argument n=%d is less than 10", n)
}
In languages like Java, it feels very tempting to let errors bubble up and then let the stack trace take care of explaining what went wrong, but it is often insufficient and may result in hours of debugging. I feel like Go makes it very easy to add extra context to errors, and if you foster the practice of adding context every time you return an errlr, it will be much richer than a stack trace.