The nil interface trap
I lost an hour today to an error value that was plainly nil and just as plainly refused to compare equal to nil.
The reduced version looked like this:
type problem struct{}
func (*problem) Error() string { return "problem" }
func check() error {
var p *problem
return p
}
fmt.Println(check() == nil) // false
My first theory involved compiler spite. The real explanation is less personal: an interface value contains a dynamic type and a dynamic value. check returns an interface containing *problem and a nil pointer. The pointer is nil, but the interface’s type word is not, so the interface itself is not nil.
Printing %#v made the situation clearer:
(*main.problem)(nil)
The fix was not reflection or a clever nil helper. It was to return a literal nil when there is no error:
func check() error {
var p *problem
if p == nil {
return nil
}
return p
}
This matters most with error, because callers naturally write if err != nil. I now keep concrete pointer errors inside the function and only convert them to error on an actual failure. Interfaces are two-word descriptions, not magic boxes. Remembering that is cheaper than another hour of accusing the compiler.