json: cannot unmarshal string into Go struct field
Go was able to parse the JSON, but one of its values doesn’t fit the field you’re decoding it into. The message tells you which one. In cannot unmarshal string into Go struct field User.age of type int, the JSON has a string, the field is User.age, and that field is an int. Go won’t turn a string into an int on its own, so you either change the struct or tell Go how to read the value.
Quick fix
- Find the field from the message in your struct, and look at the value the JSON actually has for it.
- If the struct has the wrong type, change it to match what the API sends.
- If the API puts numbers or booleans in quotes, like
"age": "34", add,stringto the field’s tag or usejson.Number.
An example
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
var u User
err := json.Unmarshal([]byte(`{"id": 1, "name": "Maya", "age": "34"}`), &u)
// json: cannot unmarshal string into Go struct field User.age of type intThe API sent the age in quotes, so the JSON value is the string "34", while Age is an int.
One thing to watch for: Unmarshal doesn’t stop at the field that failed. It keeps going and fills in everything else it can, so here u.ID is 1 and u.Name is “Maya”, and only Age is left at 0. If your code logs the error and carries on, it ends up working with a struct that’s partly empty.
What each version means
json: cannot unmarshal string into Go struct field User.age of type int | The number came in quotes, like "34". Fix |
json: cannot unmarshal number into Go struct field User.name of type string | The JSON has a number and the field is a string. This happens a lot with IDs. |
json: cannot unmarshal number 34.5 into Go struct field User.age of type int | A number with a decimal part can’t go into an int. Use float64. |
json: cannot unmarshal string into Go struct field User.active of type bool | The boolean came in quotes, like "true". Fix |
json: cannot unmarshal object into Go struct field User.name of type string | The value is an object, like {"first": "Maya"}. Make the field a struct with matching fields. |
json: cannot unmarshal string into Go struct field User.tags of type []string | The field expects a list, but the JSON has a single value. Fix |
json: cannot unmarshal array into Go value of type main.User | The JSON is a list of users. Decode it into []User. |
json: cannot unmarshal object into Go value of type []main.User | The list is inside an object, like {"data": […]}. Fix |
If the message says “Go value” instead of “Go struct field”, the problem is the whole document rather than one field. The JSON has a different shape from the type you passed, such as a list when you expected a single object. For fields inside nested structs, the message gives the full path, like address.zip.
Numbers and booleans sent as strings
Some APIs send every value as a string. Adding ,string to the tag tells Go to read the number or boolean from inside the quotes:
type User struct {
Age int `json:"age,string"`
}After that, the field only accepts the quoted form. If the API sends a plain 34, you get json: invalid use of ,string struct tag, trying to unmarshal unquoted value into int. When an API isn’t consistent about quoting, use json.Number instead. It accepts both 34 and "34", and you convert it when you use it:
type User struct {
Age json.Number `json:"age"`
}
age, err := u.Age.Int64()Responses wrapped in an object
A lot of APIs return a list inside an object, like {"data": [...], "page": 1}. If you decode that straight into []User, you get cannot unmarshal object into Go value of type []main.User. Decode it into a struct that matches the outer object, then take the list out of that:
var resp struct {
Data []User `json:"data"`
}
err := json.Unmarshal(body, &resp)
users := resp.DataA field that’s sometimes one value and sometimes a list
Some APIs send "tags": "api" when there’s a single tag and "tags": ["api", "go"] when there are several. A slice type with its own UnmarshalJSON method can accept both:
type StringList []string
func (l *StringList) UnmarshalJSON(data []byte) error {
var one string
if err := json.Unmarshal(data, &one); err == nil {
*l = StringList{one}
return nil
}
var many []string
if err := json.Unmarshal(data, &many); err != nil {
return err
}
*l = many
return nil
}
type User struct {
Tags StringList `json:"tags"`
}Time fields
time.Time fields fail with a different message. Go expects times in RFC 3339 format, such as 2026-10-26T09:30:00Z, and anything else fails like this:
parsing time "2026-10-26" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "T"Here the JSON had a date with no time. Change the field to a string and parse it with time.Parse, using the layout the API actually sends. For a plain date, that layout is "2006-01-02". If the JSON itself won’t parse, you’ll see a different kind of error, which the guide to Go’s invalid character errors covers.
The same error elsewhere
| Go, json.Decoder | json: cannot unmarshal string into Go struct field User.age of type int |
|---|---|
| Python, Pydantic | Input should be a valid integer, unable to parse string as an integer |
| C#, System.Text.Json | The JSON value could not be converted to System.Int32. Path: $.age |