Even experienced go developers can get tripped up by this one edge case in golang.

In golang nil is not always equal to nil.

A variable that holds an interface can have a nil value but still pass a nil check.

An interface value is internally stored as two words:

  1. Type word – the dynamic type of the value stored in the interface.

  2. Value word – the actual value itself (or a pointer to it).

An interface is only nil if both the Type and the Value are nil.

This means that you could have a pointer with the type *int but a value equal to nil, then assign it to an interface and the interface would not be nil! This can easily translate into a panic in your go applications.

Code

package main

import (
    "fmt"
)

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

func main() {
    var i interface{}           // type=nil, value=nil
    fmt.Println("i == nil?", i == nil)

    var p *int = nil             // typed nil pointer
    i = p                        // type=*int, value=nil
    fmt.Println("i == nil?", i == nil)
    fmt.Printf("dynamic: %T, value: %v\n", i, i)

    // error example
    var me *MyErr = nil          // typed nil *MyErr
    var err error = me           // type=*MyErr, value=nil -> non-nil interface
    fmt.Println("err == nil?", err == nil)

    // Correct: when you mean no error, assign untyped nil
    err = nil
    fmt.Println("err == nil after explicit nil?", err == nil)
}

Output

i == nil? true
i == nil? false
dynamic: *int, value: <nil>
err == nil? false
err == nil after explicit nil? true