69

This example from the json.Unmarshal docs (slightly modified for simplicity to use Animal instead of []Animal) works, no errors:

Playground link of working example

// ...
var animals Animal
err := json.Unmarshal(jsonBlob, &animals)
// ...

But this slightly modified example doesn't:

Playground link of non-working example

// ...
var animals *Animal
err := json.Unmarshal(jsonBlob, animals)
// ...

It displays this obscure error that really isn't helpful (looks more like a function call than an error IMO):

json: Unmarshal(nil *main.Animal)

This appears to be because animals is an uninitialized pointer. But the docs say (emphasis mine):

Unmarshal unmarshals the JSON into the value pointed at by the pointer. If the pointer is nil, Unmarshal allocates a new value for it to point to.

So why does unmarshaling fail in the second example and show that obscure error?

(Also, is it "unmarshalling" or "unmarshaling" (one L)? The docs use both.)

1

4 Answers 4

60

You've encountered an InvalidUnmarshalError (see lines 109 and 110 in decode.go).

// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
// (The argument to Unmarshal must be a non-nil pointer.)

It seems the docs could do with some clarification as the quote above and the comment below from the Unmarshal source seem to contradict each other.

If the pointer is nil, Unmarshal allocates a new value for it to point to.

Sign up to request clarification or add additional context in comments.

Comments

54

Because your pointer is nil.

If you initialize it it works: http://play.golang.org/p/zprmV0O1fG

var animals *Animal = &Animal{}

Also, it can be spelled either way (consistency in a single doc would be nice, though): http://en.wikipedia.org/wiki/Marshalling_(computer_science)

7 Comments

Okay, but then what does this mean in the documentation for Unmarshal: "If the pointer is nil, Unmarshal allocates a new value for it to point to." Why do we have to initialize it if Unmarshal should be doing it for us?
Haha, yeah I just saw that in your question. Well, if you pass in the reference to the pointer, it also allocates it. play.golang.org/p/3KP7pPKmBp
Interesting. So is my understanding of what "pointer" means incorrect or are the docs wrong? Because all I see working here are references, not pointers.
It wouldn't be able to change the value of the pointer (where it's pointing to), without a reference to the pointer.
Perhaps the documentation about allocating a new value for pointers refers to the behavior when populating a struct with pointer fields rather than the pointer passed to Unmarshal. Consider that Unmarshal has no way to return the new pointer to the caller as the passed pointer cannot be modified by Unmarshal.
|
22

I believe the issue is that, while you can pass a pointer to nil to Unmarshal(), you can't pass a nil pointer value.

A pointer to nil would be like:

var v interface{}
json.Unmarshal(text, &v)

The value of v is nil, but the pointer to v is a non-zero pointer address. It's a non-zero pointer, which is pointing to a nil interface{} (which itself is a pointer type). Unmarshal doesn't return an error in this case.

A nil pointer would be like:

var v *interface{}
json.Unmarshal(text, v)

In this case, the type of v is pointer to an interface{}, but as with any declaration of a var in golang, the initial value of v is the type's zero-value. So v is a zero-value pointer, which means it isn't pointing to any valid place in memory.

As mentioned in the https://stackoverflow.com/a/20478917/387176, json.Unmarshal() needs a valid pointer to something, so it can change the something (be it a zero value struct, or a pointer) in place.

Comments

1

I had a similiar condition before but in a different case. It is related with concept of interface in Go. If a function declares a interface as argument or return value, the caller have to pass or return the reference

In your case, json.Unmarshal accept interface as second argument

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.