DecodeJSON with byte offsets for parse failures
Go
package jsonx
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
)
// DecodeJSON decodes one JSON value into out and adds context to failures:
// byte offsets for syntax and type errors, and a clear message for truncation.
func DecodeJSON(data []byte, out any) error {
dec := json.NewDecoder(bytes.NewReader(data))
if err := dec.Decode(out); err != nil {
var syn *json.SyntaxError
var typ *json.UnmarshalTypeError
switch {
case errors.As(err, &syn):
return fmt.Errorf("invalid JSON at byte %d: %w", syn.Offset, err)
case errors.As(err, &typ):
return fmt.Errorf("field %q: expected %s at byte %d", typ.Field, typ.Type, typ.Offset)
case errors.Is(err, io.ErrUnexpectedEOF), errors.Is(err, io.EOF):
return fmt.Errorf("truncated JSON document: %w", err)
default:
return fmt.Errorf("decode JSON: %w", err)
}
}
if dec.More() {
return errors.New("unexpected trailing data after JSON value")
}
return nil
}