# How to Fix Go JSON Unmarshal Type Mismatch
JSON unmarshal type mismatch errors occur when JSON data doesn't match the expected Go struct types. This guide covers diagnosis and solutions.
Error Patterns
Type Mismatch Error
json: cannot unmarshal string into Go struct field User.age of type int
json: cannot unmarshal number into Go struct field Config.enabled of type bool
json: cannot unmarshal array into Go struct field Data.items of type stringUnexpected JSON Structure
json: cannot unmarshal object into Go value of type []string
json: cannot unmarshal string into Go value of type float64Common Causes
- 1.Number vs String - JSON has number, struct expects string
- 2.Boolean vs String - JSON has boolean, struct expects string
- 3.Array vs Single Value - JSON has array, struct expects single value
- 4.Object vs Array - JSON structure mismatch
- 5.Missing fields - JSON doesn't have expected fields
- 6.Extra fields - JSON has fields not in struct
- 7.Null values - JSON has null but struct field isn't pointer
Problematic Examples
```go type User struct { Name string Age int // JSON has "age": "25" (string) }
jsonStr := {"name": "John", "age": "25"}
var user User
err := json.Unmarshal([]byte(jsonStr), &user)
// Error: cannot unmarshal string into Go struct field User.age of type int
```
```go type Config struct { Enabled bool // JSON has "enabled": "true" (string) }
jsonStr := {"enabled": "true"}
var config Config
err := json.Unmarshal([]byte(jsonStr), &config)
// Error: cannot unmarshal string into Go struct field Config.enabled of type bool
```
Solutions
Solution 1: Accept Multiple Types with Interface
```go type FlexibleInt struct { Value int }
func (fi *FlexibleInt) UnmarshalJSON(data []byte) error { // Try as int first var i int if err := json.Unmarshal(data, &i); err == nil { fi.Value = i return nil }
// Try as string var s string if err := json.Unmarshal(data, &s); err == nil { parsed, err := strconv.Atoi(s) if err != nil { return err } fi.Value = parsed return nil }
return fmt.Errorf("cannot unmarshal FlexibleInt") }
type User struct { Name string Age FlexibleInt // Accepts int or string } ```
Solution 2: Use json.Number for Numeric Flexibility
```go type Data struct { ID json.Number // Can be string or number }
func (d *Data) GetID() (int64, error) { return d.ID.Int64() } ```
Solution 3: Custom Unmarshaler for Bool from String
```go type FlexibleBool struct { Value bool }
func (fb *FlexibleBool) UnmarshalJSON(data []byte) error { // Try as bool var b bool if err := json.Unmarshal(data, &b); err == nil { fb.Value = b return nil }
// Try as string var s string if err := json.Unmarshal(data, &s); err == nil { switch strings.ToLower(s) { case "true", "yes", "1", "on": fb.Value = true return nil case "false", "no", "0", "off": fb.Value = false return nil } return fmt.Errorf("invalid bool string: %s", s) }
return fmt.Errorf("cannot unmarshal FlexibleBool") } ```
Solution 4: Use Pointer for Optional/Null Fields
```go type User struct { Name string Age *int // Can handle null in JSON Email *string // Optional field }
jsonStr := {"name": "John", "age": null, "email": null}
var user User
json.Unmarshal([]byte(jsonStr), &user)
// Age and Email will be nil pointers
```
Solution 5: Accept Array or Single Value
```go type FlexibleArray struct { Values []string }
func (fa *FlexibleArray) UnmarshalJSON(data []byte) error { // Try as array var arr []string if err := json.Unmarshal(data, &arr); err == nil { fa.Values = arr return nil }
// Try as single string var single string if err := json.Unmarshal(data, &single); err == nil { fa.Values = []string{single} return nil }
return fmt.Errorf("cannot unmarshal FlexibleArray") } ```
Solution 6: Use RawMessage for Delayed Parsing
```go type Message struct { Type string Data json.RawMessage // Parse later based on Type }
func handleMessage(msg Message) { switch msg.Type { case "user": var user User json.Unmarshal(msg.Data, &user) case "config": var config Config json.Unmarshal(msg.Data, &config) } } ```
Solution 7: Map for Unknown Structure
```go // Use map for flexible structure var data map[string]interface{} json.Unmarshal(jsonBytes, &data)
// Access fields dynamically if age, ok := data["age"]; ok { switch v := age.(type) { case int: fmt.Println(v) case float64: // JSON numbers are float64 fmt.Println(int(v)) case string: parsed, _ := strconv.Atoi(v) fmt.Println(parsed) } } ```
Solution 8: Strict vs Lenient Parsing
go
// Lenient: Ignore unknown fields (default behavior)
type Config struct {
Name string json:"name"`
}
// Strict: Error on unknown fields
type StrictConfig struct {
Name string json:"name"
}
func strictUnmarshal(data []byte, v interface{}) error { dec := json.NewDecoder(bytes.NewReader(data)) dec.DisallowUnknownFields() return dec.Decode(v) } ```
Field Name Mapping
Use json Tags for Different Names
type User struct {
Name string `json:"name"`
Age int `json:"age,omitempty"` // Skip if empty
Email string `json:"email,omitempty"`
FullName string `json:"full_name"` // Snake case in JSON
APIKey string `json:"apiKey"` // Camel case
}Handle Case Sensitivity
```go // JSON field names are case-insensitive by default // But tags should match for clarity
type Data struct {
ID int json:"id" // Matches "id", "ID", "Id"
}
```
Debugging JSON Issues
Debug Unknown Structure
```go func debugJSON(data []byte) { var raw map[string]interface{} json.Unmarshal(data, &raw)
for key, val := range raw { fmt.Printf("%s: %T = %v\n", key, val, val) } } ```
Pretty Print JSON
func prettyPrintJSON(data []byte) string {
var buf bytes.Buffer
json.Indent(&buf, data, "", " ")
return buf.String()
}Validation Pattern
go
type ValidatedUser struct {
Name string json:"name"
Age int json:"age"`
}
func (u *ValidatedUser) Validate() error { if u.Name == "" { return fmt.Errorf("name is required") } if u.Age < 0 || u.Age > 150 { return fmt.Errorf("age must be between 0 and 150") } return nil }
func parseAndValidate(data []byte) (*ValidatedUser, error) { var user ValidatedUser if err := json.Unmarshal(data, &user); err != nil { return nil, err } if err := user.Validate(); err != nil { return nil, err } return &user, nil } ```
Prevention Tips
- 1.Use json tags - Always specify JSON field names explicitly
- 2.Use pointers for optional/null fields
- 3.Implement custom unmarshalers for flexible types
- 4.Validate after unmarshal - Don't trust JSON data
- 5.Test with various JSON inputs - Include edge cases
Related Errors
invalid character- Malformed JSON syntaxunexpected end of JSON- Incomplete JSON datajson: unknown field- DisallowUnknownFields triggered