What input will cause golang's json.Marshal to return an error?

33,279

Solution 1

Just to complement Jonathan's answer, the json.Marshal function can return two types of errors: UnsupportedTypeError or UnsupportedValueError

The first one can be caused, as Jonathan said by trying to Marshal an invalid type:

_, err := json.Marshal(make(chan int))
_, ok := err.(*json.UnsupportedTypeError) // ok == true

On the other hand you can also have the Marshal function return an error by passing an invalid value:

_, err := json.Marshal(math.Inf(1))
_, ok := err.(*json.UnsupportedValueError) // ok == true

Solution 2

Update: now using a channel instead of a map[int]int to elicit the error


Go-specific structures,e.g. func or chan refuse to serialize:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    value := make(chan int)
    _, err := json.Marshal(value)
    fmt.Println(err)
}

Solution 3

Read the source code you can found such a function to judge a encoder if not exist will return marshal error: https://github.com/golang/go/blob/master/src/encoding/json/encode.go

func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
    // ignored
    switch t.Kind() {
    case reflect.Bool:
        return boolEncoder
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        return intEncoder
    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
        return uintEncoder
    case reflect.Float32:
        return float32Encoder
    case reflect.Float64:
        return float64Encoder
    case reflect.String:
        return stringEncoder
    case reflect.Interface:
        return interfaceEncoder
    case reflect.Struct:
        return newStructEncoder(t)
    case reflect.Map:
        return newMapEncoder(t)
    case reflect.Slice:
        return newSliceEncoder(t)
    case reflect.Array:
        return newArrayEncoder(t)
    case reflect.Ptr:
        return newPtrEncoder(t)
    default:
        return unsupportedTypeEncoder
    }
}

We can find all kinds enum at https://github.com/golang/go/blob/master/src/reflect/type.go

So it's not hard to see that kinds not in above function are unable to marshal:

UnsafePointer,Complex64,Complex128,Chan,Func

Examples:

        json.Marshal(unsafe.Pointer(nil)) // UnsafePointer
        json.Marshal(complex64(1))        // Complex64
        json.Marshal(complex128(1))       // Complex128
        json.Marshal(make(chan struct{})) // Chan
        json.Marshal(func() {})           // Func
Share:
33,279
mdwhatcott
Author by

mdwhatcott

I'm a software developer at Clean Coders Studio (https://cleancoders.com/studio).

Updated on January 17, 2021

Comments

  • mdwhatcott
    mdwhatcott over 3 years

    From the docs:

    JSON cannot represent cyclic data structures and Marshal does not handle them. Passing cyclic structures to Marshal will result in an infinite recursion.

    I've experienced this situation, which results in a runtime panic.

    What I'm wondering is if anyone can provide a working program that demonstrates a non-panic situation where json.Marshal returns a non-nil error. The best answers would clearly include the inputs used.