jserrors.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright 2020-2022 The NATS Authors
  2. // Licensed under the Apache License, Version 2.0 (the "License");
  3. // you may not use this file except in compliance with the License.
  4. // You may obtain a copy of the License at
  5. //
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package nats
  14. import (
  15. "errors"
  16. "fmt"
  17. )
  18. var (
  19. // API errors
  20. // ErrJetStreamNotEnabled is an error returned when JetStream is not enabled for an account.
  21. ErrJetStreamNotEnabled JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeJetStreamNotEnabled, Description: "jetstream not enabled", Code: 503}}
  22. // ErrJetStreamNotEnabledForAccount is an error returned when JetStream is not enabled for an account.
  23. ErrJetStreamNotEnabledForAccount JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeJetStreamNotEnabledForAccount, Description: "jetstream not enabled for account", Code: 503}}
  24. // ErrStreamNotFound is an error returned when stream with given name does not exist.
  25. ErrStreamNotFound JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeStreamNotFound, Description: "stream not found", Code: 404}}
  26. // ErrStreamNameAlreadyInUse is returned when a stream with given name already exists and has a different configuration.
  27. ErrStreamNameAlreadyInUse JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeStreamNameInUse, Description: "stream name already in use", Code: 400}}
  28. // ErrConsumerNotFound is an error returned when consumer with given name does not exist.
  29. ErrConsumerNotFound JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeConsumerNotFound, Description: "consumer not found", Code: 404}}
  30. // ErrMsgNotFound is returned when message with provided sequence number does npt exist.
  31. ErrMsgNotFound JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeMessageNotFound, Description: "message not found", Code: 404}}
  32. // ErrBadRequest is returned when invalid request is sent to JetStream API.
  33. ErrBadRequest JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeBadRequest, Description: "bad request", Code: 400}}
  34. // Client errors
  35. // ErrConsumerNameAlreadyInUse is an error returned when consumer with given name already exists.
  36. ErrConsumerNameAlreadyInUse JetStreamError = &jsError{message: "consumer name already in use"}
  37. // ErrConsumerNotActive is an error returned when consumer is not active.
  38. ErrConsumerNotActive JetStreamError = &jsError{message: "consumer not active"}
  39. // ErrInvalidJSAck is returned when JetStream ack from message publish is invalid.
  40. ErrInvalidJSAck JetStreamError = &jsError{message: "invalid jetstream publish response"}
  41. // ErrStreamConfigRequired is returned when empty stream configuration is supplied to add/update stream.
  42. ErrStreamConfigRequired JetStreamError = &jsError{message: "stream configuration is required"}
  43. // ErrStreamNameRequired is returned when the provided stream name is empty.
  44. ErrStreamNameRequired JetStreamError = &jsError{message: "stream name is required"}
  45. // ErrConsumerNameRequired is returned when the provided consumer durable name is empty.
  46. ErrConsumerNameRequired JetStreamError = &jsError{message: "consumer name is required"}
  47. // ErrConsumerConfigRequired is returned when empty consumer consuguration is supplied to add/update consumer.
  48. ErrConsumerConfigRequired JetStreamError = &jsError{message: "consumer configuration is required"}
  49. // ErrPullSubscribeToPushConsumer is returned when attempting to use PullSubscribe on push consumer.
  50. ErrPullSubscribeToPushConsumer JetStreamError = &jsError{message: "cannot pull subscribe to push based consumer"}
  51. // ErrPullSubscribeRequired is returned when attempting to use subscribe methods not suitable for pull consumers for pull consumers.
  52. ErrPullSubscribeRequired JetStreamError = &jsError{message: "must use pull subscribe to bind to pull based consumer"}
  53. // ErrMsgAlreadyAckd is returned when attempting to acknowledge message more than once.
  54. ErrMsgAlreadyAckd JetStreamError = &jsError{message: "message was already acknowledged"}
  55. // ErrNoStreamResponse is returned when there is no response from stream (e.g. no responders error).
  56. ErrNoStreamResponse JetStreamError = &jsError{message: "no response from stream"}
  57. // ErrNotJSMessage is returned when attempting to get metadata from non JetStream message .
  58. ErrNotJSMessage JetStreamError = &jsError{message: "not a jetstream message"}
  59. // ErrInvalidStreamName is returned when the provided stream name is invalid (contains '.' or ' ').
  60. ErrInvalidStreamName JetStreamError = &jsError{message: "invalid stream name"}
  61. // ErrInvalidConsumerName is returned when the provided consumer name is invalid (contains '.' or ' ').
  62. ErrInvalidConsumerName JetStreamError = &jsError{message: "invalid consumer name"}
  63. // ErrNoMatchingStream is returned when stream lookup by subject is unsuccessful.
  64. ErrNoMatchingStream JetStreamError = &jsError{message: "no stream matches subject"}
  65. // ErrSubjectMismatch is returned when the provided subject does not match consumer's filter subject.
  66. ErrSubjectMismatch JetStreamError = &jsError{message: "subject does not match consumer"}
  67. // ErrContextAndTimeout is returned when attempting to use both context and timeout.
  68. ErrContextAndTimeout JetStreamError = &jsError{message: "context and timeout can not both be set"}
  69. // ErrCantAckIfConsumerAckNone is returned when attempting to ack a message for consumer with AckNone policy set.
  70. ErrCantAckIfConsumerAckNone JetStreamError = &jsError{message: "cannot acknowledge a message for a consumer with AckNone policy"}
  71. // ErrConsumerDeleted is returned when attempting to send pull request to a consumer which does not exist
  72. ErrConsumerDeleted JetStreamError = &jsError{message: "consumer deleted"}
  73. // ErrConsumerLeadershipChanged is returned when pending requests are no longer valid after leadership has changed
  74. ErrConsumerLeadershipChanged JetStreamError = &jsError{message: "Leadership Changed"}
  75. // DEPRECATED: ErrInvalidDurableName is no longer returned and will be removed in future releases.
  76. // Use ErrInvalidConsumerName instead.
  77. ErrInvalidDurableName = errors.New("nats: invalid durable name")
  78. )
  79. // Error code represents JetStream error codes returned by the API
  80. type ErrorCode uint16
  81. const (
  82. JSErrCodeJetStreamNotEnabledForAccount ErrorCode = 10039
  83. JSErrCodeJetStreamNotEnabled ErrorCode = 10076
  84. JSErrCodeInsufficientResourcesErr ErrorCode = 10023
  85. JSErrCodeStreamNotFound ErrorCode = 10059
  86. JSErrCodeStreamNameInUse ErrorCode = 10058
  87. JSErrCodeConsumerNotFound ErrorCode = 10014
  88. JSErrCodeConsumerNameExists ErrorCode = 10013
  89. JSErrCodeConsumerAlreadyExists ErrorCode = 10105
  90. JSErrCodeMessageNotFound ErrorCode = 10037
  91. JSErrCodeBadRequest ErrorCode = 10003
  92. JSErrCodeStreamWrongLastSequence ErrorCode = 10071
  93. )
  94. // APIError is included in all API responses if there was an error.
  95. type APIError struct {
  96. Code int `json:"code"`
  97. ErrorCode ErrorCode `json:"err_code"`
  98. Description string `json:"description,omitempty"`
  99. }
  100. // Error prints the JetStream API error code and description
  101. func (e *APIError) Error() string {
  102. return fmt.Sprintf("nats: %s", e.Description)
  103. }
  104. // APIError implements the JetStreamError interface.
  105. func (e *APIError) APIError() *APIError {
  106. return e
  107. }
  108. // Is matches against an APIError.
  109. func (e *APIError) Is(err error) bool {
  110. if e == nil {
  111. return false
  112. }
  113. // Extract internal APIError to match against.
  114. var aerr *APIError
  115. ok := errors.As(err, &aerr)
  116. if !ok {
  117. return ok
  118. }
  119. return e.ErrorCode == aerr.ErrorCode
  120. }
  121. // JetStreamError is an error result that happens when using JetStream.
  122. // In case of client-side error, `APIError()` returns nil
  123. type JetStreamError interface {
  124. APIError() *APIError
  125. error
  126. }
  127. type jsError struct {
  128. apiErr *APIError
  129. message string
  130. }
  131. func (err *jsError) APIError() *APIError {
  132. return err.apiErr
  133. }
  134. func (err *jsError) Error() string {
  135. if err.apiErr != nil && err.apiErr.Description != "" {
  136. return err.apiErr.Error()
  137. }
  138. return fmt.Sprintf("nats: %s", err.message)
  139. }
  140. func (err *jsError) Unwrap() error {
  141. // Allow matching to embedded APIError in case there is one.
  142. if err.apiErr == nil {
  143. return nil
  144. }
  145. return err.apiErr
  146. }