Interfaces · 3 MIN READ

A nil pointer in an interface is not a nil interface

Explain why err != nil can be true when the error is nil.

An interface value holds a dynamic type and a dynamic value. It is nil only when it holds neither. Assigning a nil *MyError to an error variable preserves the pointer type, so err != nil is true even though its contained pointer is nil.

When a function returns an error interface, return literal nil on the success path rather than a typed nil pointer. Calling a method on an interface holding a nil pointer is safe only if that method deliberately supports a nil receiver.

SEE THE IDEA

An interface carries a type and a value

  1. 01

    Nil interface

    go
    var x any

    No dynamic type and no value

  2. 02

    Typed nil

    go
    var p *Item = nil

    A pointer type with a nil value

  3. 03

    Boxed pointer

    go
    x = p

    Dynamic type exists, so x != nil

Both parts must be absent for the interface itself to be nil.

In practice

An interface holding a typed nil pointer still has a dynamic type. This commonly appears when a function returns an error interface from a typed pointer variable. Return a literal nil on the success path, and make nil-receiver behavior explicit for methods intended to support it.

Watch out

An interface nil check does not prove that calling a method on the contained value is safe.

Official reference ↗

Read and predict

go
package main

import "fmt"

type PathError struct{ Path string }

func (e *PathError) Error() string { return "bad path: " + e.Path }

func find(name string) *PathError { return nil }

func check(name string) error { return find(name) }

func main() {
	fmt.Println(check("ok") == nil)
}

Does this print true or false, and why?

Try it yourself

Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.

Progress stays in this browser. No account needed.