Skip to content

Commit

Permalink
Add error details to invalid JetStream JSON errors (#5868)
Browse files Browse the repository at this point in the history
Currently failures to unmarshal only give a vague error of "invalid
JSON", this adds the original error to it as context.

Before:

````
invalid JSON
````

After:

```
invalid JSON: invalid character '\"' after object key
```

Related to but **not** dependent on
#5858

Signed-off-by: Casper Beyer <[email protected]>
  • Loading branch information
derekcollison authored Sep 11, 2024
2 parents a07bde9 + 3ddc015 commit 054c03a
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 36 deletions.
2 changes: 1 addition & 1 deletion server/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@
"constant": "JSInvalidJSONErr",
"code": 400,
"error_code": 10025,
"description": "invalid JSON",
"description": "invalid JSON: {err}",
"comment": "",
"help": "",
"url": "",
Expand Down
40 changes: 20 additions & 20 deletions server/jetstream_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,7 @@ func (s *Server) jsTemplateCreateRequest(sub *subscription, c *client, _ *Accoun

var cfg StreamTemplateConfig
if err := json.Unmarshal(msg, &cfg); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -1234,7 +1234,7 @@ func (s *Server) jsTemplateNamesRequest(sub *subscription, c *client, _ *Account
if !isEmptyRequest(msg) {
var req JSApiStreamTemplatesRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -1417,7 +1417,7 @@ func (s *Server) jsStreamCreateRequest(sub *subscription, c *client, _ *Account,

var cfg StreamConfigRequest
if err := json.Unmarshal(msg, &cfg); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -1528,7 +1528,7 @@ func (s *Server) jsStreamUpdateRequest(sub *subscription, c *client, _ *Account,
}
var ncfg StreamConfigRequest
if err := json.Unmarshal(msg, &ncfg); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -1627,7 +1627,7 @@ func (s *Server) jsStreamNamesRequest(sub *subscription, c *client, _ *Account,
if !isEmptyRequest(msg) {
var req JSApiStreamNamesRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -1757,7 +1757,7 @@ func (s *Server) jsStreamListRequest(sub *subscription, c *client, _ *Account, s
if !isEmptyRequest(msg) {
var req JSApiStreamListRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -1927,7 +1927,7 @@ func (s *Server) jsStreamInfoRequest(sub *subscription, c *client, a *Account, s
if !isEmptyRequest(msg) {
var req JSApiStreamInfoRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -2284,7 +2284,7 @@ func (s *Server) jsStreamRemovePeerRequest(sub *subscription, c *client, _ *Acco

var req JSApiStreamRemovePeerRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -2364,7 +2364,7 @@ func (s *Server) jsLeaderServerRemoveRequest(sub *subscription, c *client, _ *Ac

var req JSApiMetaServerRemoveRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -2467,7 +2467,7 @@ func (s *Server) jsLeaderServerStreamMoveRequest(sub *subscription, c *client, _

var req JSApiMetaServerStreamMoveRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -2811,7 +2811,7 @@ func (s *Server) jsLeaderStepDownRequest(sub *subscription, c *client, _ *Accoun
if !isEmptyRequest(msg) {
var req JSApiLeaderStepdownRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -3017,7 +3017,7 @@ func (s *Server) jsMsgDeleteRequest(sub *subscription, c *client, _ *Account, su
}
var req JSApiMsgDeleteRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -3136,7 +3136,7 @@ func (s *Server) jsMsgGetRequest(sub *subscription, c *client, _ *Account, subje
}
var req JSApiMsgGetRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -3279,7 +3279,7 @@ func (s *Server) jsStreamPurgeRequest(sub *subscription, c *client, _ *Account,
if !isEmptyRequest(msg) {
var req JSApiStreamPurgeRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -3369,7 +3369,7 @@ func (s *Server) jsStreamRestoreRequest(sub *subscription, c *client, _ *Account

var req JSApiStreamRestoreRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -3672,7 +3672,7 @@ func (s *Server) jsStreamSnapshotRequest(sub *subscription, c *client, _ *Accoun

var req JSApiStreamSnapshotRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, smsg, s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -3870,7 +3870,7 @@ func (s *Server) jsConsumerCreateRequest(sub *subscription, c *client, a *Accoun

var req CreateConsumerRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -4112,7 +4112,7 @@ func (s *Server) jsConsumerNamesRequest(sub *subscription, c *client, _ *Account
if !isEmptyRequest(msg) {
var req JSApiConsumersRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -4234,7 +4234,7 @@ func (s *Server) jsConsumerListRequest(sub *subscription, c *client, _ *Account,
if !isEmptyRequest(msg) {
var req JSApiConsumersRequest
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down Expand Up @@ -4545,7 +4545,7 @@ func (s *Server) jsConsumerPauseRequest(sub *subscription, c *client, _ *Account

if !isEmptyRequest(msg) {
if err := json.Unmarshal(msg, &req); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
Expand Down
16 changes: 11 additions & 5 deletions server/jetstream_errors_generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ const (
// JSInsufficientResourcesErr insufficient resources
JSInsufficientResourcesErr ErrorIdentifier = 10023

// JSInvalidJSONErr invalid JSON
// JSInvalidJSONErr invalid JSON: {err}
JSInvalidJSONErr ErrorIdentifier = 10025

// JSMaximumConsumersLimitErr maximum consumers limit reached
Expand Down Expand Up @@ -550,7 +550,7 @@ var (
JSConsumerWQRequiresExplicitAckErr: {Code: 400, ErrCode: 10098, Description: "workqueue stream requires explicit ack"},
JSConsumerWithFlowControlNeedsHeartbeats: {Code: 400, ErrCode: 10108, Description: "consumer with flow control also needs heartbeats"},
JSInsufficientResourcesErr: {Code: 503, ErrCode: 10023, Description: "insufficient resources"},
JSInvalidJSONErr: {Code: 400, ErrCode: 10025, Description: "invalid JSON"},
JSInvalidJSONErr: {Code: 400, ErrCode: 10025, Description: "invalid JSON: {err}"},
JSMaximumConsumersLimitErr: {Code: 400, ErrCode: 10026, Description: "maximum consumers limit reached"},
JSMaximumStreamsLimitErr: {Code: 400, ErrCode: 10027, Description: "maximum number of streams reached"},
JSMemoryResourcesExceededErr: {Code: 500, ErrCode: 10028, Description: "insufficient memory resources available"},
Expand Down Expand Up @@ -1437,14 +1437,20 @@ func NewJSInsufficientResourcesError(opts ...ErrorOption) *ApiError {
return ApiErrors[JSInsufficientResourcesErr]
}

// NewJSInvalidJSONError creates a new JSInvalidJSONErr error: "invalid JSON"
func NewJSInvalidJSONError(opts ...ErrorOption) *ApiError {
// NewJSInvalidJSONError creates a new JSInvalidJSONErr error: "invalid JSON: {err}"
func NewJSInvalidJSONError(err error, opts ...ErrorOption) *ApiError {
eopts := parseOpts(opts)
if ae, ok := eopts.err.(*ApiError); ok {
return ae
}

return ApiErrors[JSInvalidJSONErr]
e := ApiErrors[JSInvalidJSONErr]
args := e.toReplacerArgs([]interface{}{"{err}", err})
return &ApiError{
Code: e.Code,
ErrCode: e.ErrCode,
Description: strings.NewReplacer(args...).Replace(e.Description),
}
}

// NewJSMaximumConsumersLimitError creates a new JSMaximumConsumersLimitErr error: "maximum consumers limit reached"
Expand Down
20 changes: 10 additions & 10 deletions server/mqtt.go
Original file line number Diff line number Diff line change
Expand Up @@ -1912,61 +1912,61 @@ func (as *mqttAccountSessionManager) processJSAPIReplies(_ *subscription, pc *cl
case mqttJSAStreamCreate:
var resp = &JSApiStreamCreateResponse{}
if err := json.Unmarshal(msg, resp); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
}
out(resp)
case mqttJSAStreamUpdate:
var resp = &JSApiStreamUpdateResponse{}
if err := json.Unmarshal(msg, resp); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
}
out(resp)
case mqttJSAStreamLookup:
var resp = &JSApiStreamInfoResponse{}
if err := json.Unmarshal(msg, &resp); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
}
out(resp)
case mqttJSAStreamDel:
var resp = &JSApiStreamDeleteResponse{}
if err := json.Unmarshal(msg, &resp); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
}
out(resp)
case mqttJSAConsumerCreate:
var resp = &JSApiConsumerCreateResponse{}
if err := json.Unmarshal(msg, resp); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
}
out(resp)
case mqttJSAConsumerDel:
var resp = &JSApiConsumerDeleteResponse{}
if err := json.Unmarshal(msg, resp); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
}
out(resp)
case mqttJSAMsgStore, mqttJSASessPersist:
var resp = &JSPubAckResponse{}
if err := json.Unmarshal(msg, resp); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
}
out(resp)
case mqttJSAMsgLoad:
var resp = &JSApiMsgGetResponse{}
if err := json.Unmarshal(msg, &resp); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
}
out(resp)
case mqttJSAStreamNames:
var resp = &JSApiStreamNamesResponse{}
if err := json.Unmarshal(msg, resp); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
}
out(resp)
case mqttJSAMsgDelete:
var resp = &JSApiMsgDeleteResponse{}
if err := json.Unmarshal(msg, resp); err != nil {
resp.Error = NewJSInvalidJSONError()
resp.Error = NewJSInvalidJSONError(err)
}
out(resp)
default:
Expand Down

0 comments on commit 054c03a

Please sign in to comment.