package server import ( "encoding/json" "fmt" json2 "github.com/aarondl/json" "github.com/getsentry/sentry-go" ) // An error returned by version 2 of the API. type APIError2 struct { Code int `json:"code"` ID *sentry.EventID `json:"id,omitempty"` Message string `json:"message,omitempty"` Details string `json:"details,omitempty"` Errors map[string][]ModelParseError `json:"errors,omitempty"` RatelimitReset *int `json:"ratelimit_reset,omitempty"` Status int `json:"-"` } func (e APIError2) Error() string { if e.Message == "" { e.Message = errCodeMessages[e.Code] } if e.Details != "" { return fmt.Sprintf("%s (code: %d) (%s)", e.Message, e.Code, e.Details) } return fmt.Sprintf("%s (code: %d)", e.Message, e.Code) } // Returns a new error in APIv2 format. func NewV2Error(code int, details string, parseErrors ...ModelParseError) APIError2 { var errors map[string][]ModelParseError if len(parseErrors) != 0 { errors = make(map[string][]ModelParseError) for _, p := range parseErrors { errors[p.Key] = append(errors[p.Key], p) } } return APIError2{ Code: code, Message: errCodeMessages[code], Details: details, Errors: errors, Status: errCodeStatuses[code], } } type ModelParseError struct { Message string `json:"message,omitempty"` MaxLength int `json:"max_length,omitempty"` ActualLength int `json:"actual_length,omitempty"` ExpectedValues []any `json:"expected_values,omitempty"` ActualValue any `json:"actual_value,omitempty"` ExpectedType string `json:"expected_type,omitempty"` ActualType string `json:"actual_type,omitempty"` Key string `json:"-"` } func NewModelParseError(key, message string) ModelParseError { return NewModelParseErrorWithLength(key, message, 0, 0) } func NewModelParseErrorWithLength(key, message string, maxLength, actualLength int) ModelParseError { return ModelParseError{ Key: key, Message: message, MaxLength: maxLength, ActualLength: actualLength, } } func NewModelParseErrorWithValues(key, message string, expectedValues []any, actualValue any) ModelParseError { return ModelParseError{ Key: key, Message: message, ExpectedValues: expectedValues, ActualValue: actualValue, } } func ParseJSONError(err error) *ModelParseError { switch pe := err.(type) { case *json.UnmarshalTypeError: key := pe.Field if key == "" { key = "parse" } return &ModelParseError{ Key: key, ExpectedType: pe.Type.String(), ActualType: pe.Value, } case *json2.UnmarshalTypeError: // TODO: remove the need for this, somehow // This seems to be a bug in the key := pe.Field if key == "" { key = "parse" } return &ModelParseError{ Key: key, Message: "Invalid type passed for a field. Make sure your types match those in the documentation.", ExpectedType: pe.Type.String(), ActualType: pe.Value, } } return nil }