go: panic: reflect: call of reflect.Value.IsZero on zero Value
What version of Go are you using (go version)?
$ go version go version go1.16.4 linux/amd64
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env)?
Operating System is XUbuntu 20.10 (amd64). CPU is Intel Xeon E5-2678 v3
GOARCH=“amd64” GOHOSTARCH=“amd64” GOHOSTOS=“linux” GOOS=“linux”
go env Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/home/***/.cache/go-build" GOENV="/home/***/.config/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/home/***/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/home/***/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GOVCS="" GOVERSION="go1.16.4" GCCGO="gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/dev/null" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build740936505=/tmp/go-build -gno-record-gcc-switches"
What did you do?
I try to run the IsZero() Method on an Object of reflect.Value Type.
In the Debugger I reach the Code which in Comments is said to be unreachable.
panic: reflect: call of reflect.Value.IsZero on zero Value
goroutine 1 [running]:
reflect.Value.IsZero(0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/reflect/value.go:1134 +0x70b
// IsZero reports whether v is the zero value for its type.
// It panics if the argument is invalid.
func (v Value) IsZero() bool {
switch v.kind() {
//...
default:
// This should never happens, but will act as a safeguard for
// later, as a default value doesn't makes sense here.
panic(&ValueError{"reflect.Value.IsZero", v.Kind()})
}
}
https://play.golang.org/p/o5j2PKXxpwJ
package main
import (
"encoding/json"
"errors"
"fmt"
"log"
"reflect"
)
type JsonObject = map[string]interface{}
type ResponseRaw struct {
Records []JsonObject
}
func main() {
text := `[{"x": 1, "y": 2}, {"z": 3, "zz": 4, "step": 123}, {}, {"id": 999}, {"q": "test", "lto": {"a": 8, "step": 456}}, null]`
rr, err := parseValidJson([]byte(text))
if err != nil {
log.Println(err)
}
fmt.Println("rr:", rr)
}
func parseValidJson(jsonText []byte) (rr *ResponseRaw, err error) {
responseAnonymous := make([]interface{}, 0)
err = json.Unmarshal(jsonText, &responseAnonymous)
if err != nil {
return nil, err
}
rr = &ResponseRaw{
Records: make([]JsonObject, 0),
}
for _, arrayItem := range responseAnonymous {
arrayItemAsJsonObject, ok := arrayItem.(JsonObject)
if !ok {
arrayItemValue := reflect.ValueOf(arrayItem)
// Here we may receive an empty Value, i.e. reflect.Value{}.
// When we receive it and check it for Zero Value, we reach that
// Part of the Code which should be unreachable.
if arrayItemValue.IsZero() {
continue
}
if arrayItemValue.IsNil() {
continue
}
// The built-in JSON Parser thinks that an empty Object '{}' is an
// empty Slice of Objects. It may be a Bug in the Parser.
arrayItemType := reflect.TypeOf(arrayItem)
if arrayItemType.Kind() == reflect.Slice {
continue
}
return nil, errors.New("json object parsing error")
}
rr.Records = append(rr.Records, arrayItemAsJsonObject)
}
return rr, nil
}
What did you expect to see?
I expected to see the reflect.Value.IsZero() Method returning a boolean Value.
What did you see instead?
I saw the reflect.Value.IsZero() Method reaching the unreachable code and panicing.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 1
- Comments: 16 (4 by maintainers)
Can’t add anything useful, but will say I ended up there today as well!
Basically, one needs to call
IsValidbeforeIsZero, thanks for that clarification at least.Can’t call IsZero() on zero Value.
This panic message is counter-intuitive and confusing.
The Comments in the Library are wrong and misleading.
did a search on google and ended up here. This piece of documentation is misleading. Users would expect X.isZero() to return true when X is zero instead of a panic.
@seankhliao perhaps we could discuss how the documentation for IsZero could be improved to clarify the point you just highlighted? I do agree with @vault-thirteen that it’s not entirely clear, and the panic error message is a unhelpful.
Just wanted to put another +1 that having the documentation of other
reflectfunctions say something like: “an invalid zero value” would have saved me a lot of time trying to figure out whyIsZerowas panicking on what it was seemingly designed for. Thanks to everyone who worked through this before me so I could move forward with my project!Add a
Printflike soYou are calling
reflect.ValueOf(nil)Sincenilhas no type, it reaches the default case.