Search code examples
gogo-reflect

Why does reflecting the name (or package path) of the error type cause a panic in Go?


Using reflection to get the name or package path of the error type in Golang causes the program to panic (with panic: runtime error: invalid memory address or nil pointer dereference).

What is the reasoning for this behaviour? (Doing the same operation for other built in types returns the type name and an empty string for the package path.)

I'm interested in terms of the design of the language - I can't figure out why it's desirable for this to behave differently for error types over other built in types.

E.g:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var str string
    strType := reflect.TypeOf(str)
    fmt.Println(strType.Name()) // OK
    fmt.Println(strType.PkgPath())  // OK

    var err error
    errType := reflect.TypeOf(err)
    fmt.Println(errType.Name()) // panics
    fmt.Println(errType.PkgPath())  // also panics
}

Go playground here: https://play.golang.org/p/JBMhMkjGPEV


Solution

  • error is not special, except that it's an interface.

    reflect.TypeOf takes a single argument of type interface{}. If you call it with a non-interface value, the value and its type is wrapped in an interface{}. If you call it with an interface value, the underlying value and type is extracted from the interface, and wrapped in a new interface{} value. If you call it with an empty interface (like you're doing here, since error is an interface and it's zero-initialized), then there's no underlying value and type, and the argument to reflect.TypeOf is a new nil interface{} value. reflect.TypeOf is defined to return nil in this case, leading to your nil problems.

    I think your confusion is that the TypeOf of an interface value is the type of its underlying value, which is never an interface. You would like TypeOf of an interface value to be the interface type itself, but that's not how it works.