Skip to content
JSON Tidy
JSON errors

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

  1. Find the field from the message in your struct, and look at the value the JSON actually has for it.
  2. If the struct has the wrong type, change it to match what the API sends.
  3. If the API puts numbers or booleans in quotes, like "age": "34", add ,string to the field’s tag or use json.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 int

The 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 intThe number came in quotes, like "34". Fix
json: cannot unmarshal number into Go struct field User.name of type stringThe 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 intA 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 boolThe boolean came in quotes, like "true". Fix
json: cannot unmarshal object into Go struct field User.name of type stringThe 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 []stringThe field expects a list, but the JSON has a single value. Fix
json: cannot unmarshal array into Go value of type main.UserThe JSON is a list of users. Decode it into []User.
json: cannot unmarshal object into Go value of type []main.UserThe 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.Data

A 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.Decoderjson: cannot unmarshal string into Go struct field User.age of type int
Python, PydanticInput should be a valid integer, unable to parse string as an integer
C#, System.Text.JsonThe JSON value could not be converted to System.Int32. Path: $.age