1

I have read this question which asks whether json.Marshal can fail on any input and based on the answers it looks like for my situation it can't fail. My situation is the following:

I have a specific struct (no nesting, no arrays, just strings, ints of various types, bools). I need to marshal it into a json. Can it ever fail?

In more specific example:

type some struct {
    F1 string `json:"f1"`
    F2 uint32 `json:"f2"`
    F3 int64  `json:"f3"`
    F4 bool   `json:"f4"`
}

func doSomething(s some) (string, error) {
    data, err := json.Marshal(s)
    if err != nil {
        return "", err
    }
    return string(data), nil
}

Can doSomething ever fail? If yes, please provide an input, otherwise explain why not. Based on my current knowledge it can't.

Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
  • 2
    If a function (e.g. `json.Marshal`) returns an error value, *never assume that it can't fail unless the documentation explicitly says so*. It returns an error for a reason. – Adrian Oct 30 '17 at 13:36
  • @Adrian you missed the point of this question. The point is to figure out why can it fail. So for me it is rather *if you see some things in the documentation for which you do not see a reason, ask other people and learn something new* – Salvador Dali Oct 30 '17 at 21:25
  • You misunderstand the point of the comment, and it's echoed in the accepted answer: the function returns an error value and the documentation doesn't say it will always be nil, so it may return an error, and the cases where it may return an error may vary between Go versions. If you want to know when it may return an error under a specific Go version, read the source of the function in that version. – Adrian Oct 31 '17 at 02:21

1 Answers1

7

There are three potential error sources I can see here:

  1. strings and various UTF8 stuff

  2. int64. Numbers in JSON are usually treated as float64, so a pedantic implementation could return an error for numbers with absolute values bigger than 2^53 because they could be dangerous.

  3. reflect.

1 and 2 don't currently happen (the functions in encoding/json don't return errors or panic). I haven't dug into the code of reflect to verify 3, but this is one of those trivially testable cases. Either it fails on the first attempt or always works.

On the other hand. In the past the json encoder would return errors if strings contained invalid UTF8 characters. It no longer does that, but this points to an important principle - things change. Just because a certain error isn't returned today doesn't mean that there won't be errors in the future. The function is defined to return errors. This means that it is perfectly valid for the standard library developers to start returning new errors in the future for things that might not be errors today. So the answer is - yes, it can fail. Maybe not today but code that depends on a particular version of a standard library is bad code.

Art
  • 19,807
  • 1
  • 34
  • 60
  • Thank you very much for `int64`. I do not fully agree with "The function is defined to return errors. This means that it is perfectly valid for the standard library developers to start returning new errors" because the function can return an error operating on the interface. It does not mean that it can return an error operating on some particular example. But anyway thank you very much for an answer. – Salvador Dali Oct 30 '17 at 09:25
  • @SalvadorDali If I designed encoding/json I would make it fail for quite some possible values of your example struct. I like my encoders and decoders to be reversible, if I can't guarantee that `x == decode(encode(x))` I would return an error. encoding/json doesn't guarantee that today so it doesn't return errors, but I don't see why someone wouldn't change their mind about that in the future, it's not a very controversial principle. – Art Oct 30 '17 at 09:33