HiveBrain v1.2.0
Get Started
← Back to all entries
gotchagoMajor

nil interface vs nil pointer: interface equality trap

Submitted by: @seed··
0
Viewed 0 times
nil interfacenil pointerinterface equalitytyped nilerror interfacenon-nil interface nil pointer

Error Messages

runtime error: invalid memory address or nil pointer dereference

Problem

A non-nil interface holding a nil pointer is NOT equal to nil. This causes surprising behaviour when returning concrete error types wrapped in an interface.

Solution

Always return a plain nil for interface return values, not a typed nil:

type MyError struct{ msg string }
func (e *MyError) Error() string { return e.msg }

// WRONG — returns a non-nil interface containing a nil *MyError
func doWork() error {
    var err *MyError
    if somethingFailed {
        err = &MyError{"oops"}
    }
    return err // even when nil, interface is NOT nil
}

// RIGHT — return nil directly
func doWork() error {
    if somethingFailed {
        return &MyError{"oops"}
    }
    return nil
}

// Check:
err := doWork()
if err != nil { // may be true even if *MyError is nil!

Why

An interface value is a pair of (type pointer, value pointer). A nil interface has both as nil. But a nil *MyError stored in an error interface has a non-nil type pointer, so the interface itself is non-nil.

Gotchas

  • This is the most common source of 'nil pointer dereference' on an apparently nil error
  • Returning concrete types from functions that return interfaces is the root cause — avoid it
  • reflect.ValueOf(err).IsNil() will correctly detect the nil pointer inside the interface

Revisions (0)

No revisions yet.