JSON troubleshooting

Go JSON: cannot unmarshal string, object or array into Go value

Fix Go UnmarshalTypeError when JSON strings, numbers, objects or arrays do not match your struct fields. Read the field path, then use string tags or json.Number.

What the error means

encoding/json parsed valid JSON but could not store a value in the Go type you passed. The message names the JSON kind it found (string, number, object, array or bool), the struct and field path when the value belongs to a struct field, and the Go type. The field path uses JSON key names. Unmarshal does not stop at this error: it fills the fields it can and returns the first type error, so the destination is partly populated.

Exact messages by runtime

Messages depend on the input and runtime version. Node and Python rows were reproduced locally. Other rows cite official documentation or source. Rows marked as fragments or templates preserve the source wording and are not complete exception transcripts. Browsers and libraries may append location details.

RuntimeMessageInput and evidence
Go / encoding/jsonjson: cannot unmarshal string into Go struct field User.age of type int{"age":"42"} into a struct with Age int `json:"age"`
Source-derived from Go 1.27 decode.go; the path uses JSON key names
Go, wrapped listjson: cannot unmarshal object into Go value of type []main.Item{"items":[{"id":1}]} into []Item
Source-derived from Go 1.27 decode.go
Go, array into one valuejson: cannot unmarshal array into Go value of type main.Item[{"id":1}] into Item
Source-derived from Go 1.27 decode.go
Go, fraction into an integerjson: cannot unmarshal number 1.5 into Go struct field Item.id of type int{"id":1.5}
Source-derived: integer fields include the number literal
Go, number into a stringjson: cannot unmarshal number into Go struct field User.name of type string{"name":42}
Source-derived from Go 1.27 decode.go
Go with GOEXPERIMENT=jsonv2json: cannot unmarshal {value} into Go struct field {path} of type {type}: {detail}Built with the jsonv2 experiment
Go 1.27 experimental template; values and paths can be worded differently
C# / System.Text.JsonThe JSON value could not be converted to {0}."42" into an int property
Official .NET 10 resource template; path and location omitted

Causes you can reproduce

A number arrives as a string

Some APIs quote numbers, especially 64-bit IDs. An int field rejects the string.

GO
type User struct {
    Age int `json:"age"`
}
var u User
err := json.Unmarshal([]byte(`{"age":"42"}`), &u)
fmt.Println(err)

These fragments use encoding/json and fmt inside a Go function. A complete program appears below.

The JSON wraps the list in an object

A response such as {"items": [...]} cannot go into a slice. Decode into a struct with an Items field.

GO
type Item struct {
    ID int `json:"id"`
}
var items []Item
err := json.Unmarshal([]byte(`{"items":[{"id":1}]}`), &items)
fmt.Println(err)

These fragments use encoding/json and fmt inside a Go function. A complete program appears below.

A fraction or out-of-range number targets an integer

Integer fields reject 1.5 and values that overflow the type. The message includes the number.

GO
var item Item
err := json.Unmarshal([]byte(`{"id":1.5}`), &item)
fmt.Println(err)

These fragments use encoding/json and fmt inside a Go function. A complete program appears below.

How to fix it

  1. Read the JSON kind, the field path (Struct.key) and the Go type in the message.
  2. Decide which side is wrong. If the producer sends the wrong type, fix it there; if your struct is wrong, change the field type.
  3. For numbers that are always quoted, add the ,string tag option. For values that may be quoted or not, use json.Number, which accepts both 42 and "42".
  4. Check the error with errors.As and *json.UnmarshalTypeError. Do not use the partly filled value after an error.

Accept quoted numbers with the string option

The option applies to string, integer, floating-point and boolean fields. An unquoted number is then an error.

GO
type User struct {
    Age int `json:"age,string"` // accepts "42"
}

Accept either form with json.Number

encoding/json stores a quoted valid number in a json.Number field as well as an unquoted one. Convert it with Int64 or Float64.

GO
type User struct {
    Age json.Number `json:"age"` // accepts 42 and "42"
}

Model the wrapper and inspect type errors

A complete program. Field holds the JSON key path, and Value the JSON kind that arrived.

GO
package main

import (
    "encoding/json"
    "errors"
    "fmt"
)

type Item struct {
    ID int `json:"id"`
}

type ItemsResponse struct {
    Items []Item `json:"items"`
}

func main() {
    var resp ItemsResponse
    err := json.Unmarshal([]byte(`{"items":[{"id":1},{"id":"2"}]}`), &resp)
    var typeErr *json.UnmarshalTypeError
    if errors.As(err, &typeErr) {
        fmt.Printf("field %q: got JSON %s, want %s\n", typeErr.Field, typeErr.Value, typeErr.Type)
        return
    }
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(resp.Items)
}

Compare the JSON shape with your types

  1. Copy the exact JSON your code received, for example from a log or a failing test.
  2. Paste it into the Tool Kumar JSON viewer. The document stays in your browser.
  3. Open the tree at the property named in the error and check whether the value there is an object, an array or a single value. The JSON path finder copies the path to any value.
  4. Generate types from the same document with a converter listed under related tools, then compare them with your own classes or structs.

Frequently asked questions

Does Unmarshal stop at the first type error?

No. It skips the value that does not fit, keeps decoding, and returns the first UnmarshalTypeError at the end. The other fields are filled, so treat the result as invalid when err is not nil.

What does Go struct field User.age mean?

User is the Go struct type that holds the field, and age is the path of JSON keys to the value. Nested fields appear as a dotted path, such as items.id.

Should I decode into any to avoid the error?

Decoding into any accepts every shape, but then each value needs a type check. Prefer a struct that matches the documented JSON, and use json.RawMessage for parts you decode later.

Does GOEXPERIMENT=jsonv2 change the message?

Yes. With the experiment enabled, encoding/json uses the v2 implementation and formats type errors differently, with extra detail after a colon. The default Go 1.27 build uses the wording shown first.

Standards and diagnostic sources

RFC 8259 and ECMA-404 define JSON syntax. Diagnostic wording belongs to the parser. The table links each cited message to its source.