jserrors.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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. // ErrStreamSubjectTransformNotSupported is returned when the connected nats-server version does not support setting
  29. // the stream subject transform. If this error is returned when executing AddStream(), the stream with invalid
  30. // configuration was already created in the server.
  31. ErrStreamSubjectTransformNotSupported JetStreamError = &jsError{message: "stream subject transformation not supported by nats-server"}
  32. // ErrStreamSourceSubjectTransformNotSupported is returned when the connected nats-server version does not support setting
  33. // the stream source subject transform. If this error is returned when executing AddStream(), the stream with invalid
  34. // configuration was already created in the server.
  35. ErrStreamSourceSubjectTransformNotSupported JetStreamError = &jsError{message: "stream subject transformation not supported by nats-server"}
  36. // ErrStreamSourceNotSupported is returned when the connected nats-server version does not support setting
  37. // the stream sources. If this error is returned when executing AddStream(), the stream with invalid
  38. // configuration was already created in the server.
  39. ErrStreamSourceNotSupported JetStreamError = &jsError{message: "stream sourcing is not supported by nats-server"}
  40. // ErrStreamSourceMultipleSubjectTransformsNotSupported is returned when the connected nats-server version does not support setting
  41. // the stream sources. If this error is returned when executing AddStream(), the stream with invalid
  42. // configuration was already created in the server.
  43. ErrStreamSourceMultipleSubjectTransformsNotSupported JetStreamError = &jsError{message: "stream sourceing with multiple subject transforms not supported by nats-server"}
  44. // ErrConsumerNotFound is an error returned when consumer with given name does not exist.
  45. ErrConsumerNotFound JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeConsumerNotFound, Description: "consumer not found", Code: 404}}
  46. // ErrMsgNotFound is returned when message with provided sequence number does npt exist.
  47. ErrMsgNotFound JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeMessageNotFound, Description: "message not found", Code: 404}}
  48. // ErrBadRequest is returned when invalid request is sent to JetStream API.
  49. ErrBadRequest JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeBadRequest, Description: "bad request", Code: 400}}
  50. // ErrDuplicateFilterSubjects is returned when both FilterSubject and FilterSubjects are specified when creating consumer.
  51. ErrDuplicateFilterSubjects JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeDuplicateFilterSubjects, Description: "consumer cannot have both FilterSubject and FilterSubjects specified", Code: 500}}
  52. // ErrDuplicateFilterSubjects is returned when filter subjects overlap when creating consumer.
  53. ErrOverlappingFilterSubjects JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeOverlappingFilterSubjects, Description: "consumer subject filters cannot overlap", Code: 500}}
  54. // ErrEmptyFilter is returned when a filter in FilterSubjects is empty.
  55. ErrEmptyFilter JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeConsumerEmptyFilter, Description: "consumer filter in FilterSubjects cannot be empty", Code: 500}}
  56. // Client errors
  57. // ErrConsumerNameAlreadyInUse is an error returned when consumer with given name already exists.
  58. ErrConsumerNameAlreadyInUse JetStreamError = &jsError{message: "consumer name already in use"}
  59. // ErrConsumerNotActive is an error returned when consumer is not active.
  60. ErrConsumerNotActive JetStreamError = &jsError{message: "consumer not active"}
  61. // ErrInvalidJSAck is returned when JetStream ack from message publish is invalid.
  62. ErrInvalidJSAck JetStreamError = &jsError{message: "invalid jetstream publish response"}
  63. // ErrStreamConfigRequired is returned when empty stream configuration is supplied to add/update stream.
  64. ErrStreamConfigRequired JetStreamError = &jsError{message: "stream configuration is required"}
  65. // ErrStreamNameRequired is returned when the provided stream name is empty.
  66. ErrStreamNameRequired JetStreamError = &jsError{message: "stream name is required"}
  67. // ErrConsumerNameRequired is returned when the provided consumer durable name is empty.
  68. ErrConsumerNameRequired JetStreamError = &jsError{message: "consumer name is required"}
  69. // ErrConsumerMultipleFilterSubjectsNotSupported is returned when the connected nats-server version does not support setting
  70. // multiple filter subjects with filter_subjects field. If this error is returned when executing AddConsumer(), the consumer with invalid
  71. // configuration was already created in the server.
  72. ErrConsumerMultipleFilterSubjectsNotSupported JetStreamError = &jsError{message: "multiple consumer filter subjects not supported by nats-server"}
  73. // ErrConsumerConfigRequired is returned when empty consumer consuguration is supplied to add/update consumer.
  74. ErrConsumerConfigRequired JetStreamError = &jsError{message: "consumer configuration is required"}
  75. // ErrPullSubscribeToPushConsumer is returned when attempting to use PullSubscribe on push consumer.
  76. ErrPullSubscribeToPushConsumer JetStreamError = &jsError{message: "cannot pull subscribe to push based consumer"}
  77. // ErrPullSubscribeRequired is returned when attempting to use subscribe methods not suitable for pull consumers for pull consumers.
  78. ErrPullSubscribeRequired JetStreamError = &jsError{message: "must use pull subscribe to bind to pull based consumer"}
  79. // ErrMsgAlreadyAckd is returned when attempting to acknowledge message more than once.
  80. ErrMsgAlreadyAckd JetStreamError = &jsError{message: "message was already acknowledged"}
  81. // ErrNoStreamResponse is returned when there is no response from stream (e.g. no responders error).
  82. ErrNoStreamResponse JetStreamError = &jsError{message: "no response from stream"}
  83. // ErrNotJSMessage is returned when attempting to get metadata from non JetStream message .
  84. ErrNotJSMessage JetStreamError = &jsError{message: "not a jetstream message"}
  85. // ErrInvalidStreamName is returned when the provided stream name is invalid (contains '.' or ' ').
  86. ErrInvalidStreamName JetStreamError = &jsError{message: "invalid stream name"}
  87. // ErrInvalidConsumerName is returned when the provided consumer name is invalid (contains '.' or ' ').
  88. ErrInvalidConsumerName JetStreamError = &jsError{message: "invalid consumer name"}
  89. // ErrNoMatchingStream is returned when stream lookup by subject is unsuccessful.
  90. ErrNoMatchingStream JetStreamError = &jsError{message: "no stream matches subject"}
  91. // ErrSubjectMismatch is returned when the provided subject does not match consumer's filter subject.
  92. ErrSubjectMismatch JetStreamError = &jsError{message: "subject does not match consumer"}
  93. // ErrContextAndTimeout is returned when attempting to use both context and timeout.
  94. ErrContextAndTimeout JetStreamError = &jsError{message: "context and timeout can not both be set"}
  95. // ErrCantAckIfConsumerAckNone is returned when attempting to ack a message for consumer with AckNone policy set.
  96. ErrCantAckIfConsumerAckNone JetStreamError = &jsError{message: "cannot acknowledge a message for a consumer with AckNone policy"}
  97. // ErrConsumerDeleted is returned when attempting to send pull request to a consumer which does not exist
  98. ErrConsumerDeleted JetStreamError = &jsError{message: "consumer deleted"}
  99. // ErrConsumerLeadershipChanged is returned when pending requests are no longer valid after leadership has changed
  100. ErrConsumerLeadershipChanged JetStreamError = &jsError{message: "Leadership Changed"}
  101. // ErrNoHeartbeat is returned when no heartbeat is received from server when sending requests with pull consumer.
  102. ErrNoHeartbeat JetStreamError = &jsError{message: "no heartbeat received"}
  103. // DEPRECATED: ErrInvalidDurableName is no longer returned and will be removed in future releases.
  104. // Use ErrInvalidConsumerName instead.
  105. ErrInvalidDurableName = errors.New("nats: invalid durable name")
  106. )
  107. // Error code represents JetStream error codes returned by the API
  108. type ErrorCode uint16
  109. const (
  110. JSErrCodeJetStreamNotEnabledForAccount ErrorCode = 10039
  111. JSErrCodeJetStreamNotEnabled ErrorCode = 10076
  112. JSErrCodeInsufficientResourcesErr ErrorCode = 10023
  113. JSErrCodeStreamNotFound ErrorCode = 10059
  114. JSErrCodeStreamNameInUse ErrorCode = 10058
  115. JSErrCodeConsumerNotFound ErrorCode = 10014
  116. JSErrCodeConsumerNameExists ErrorCode = 10013
  117. JSErrCodeConsumerAlreadyExists ErrorCode = 10105
  118. JSErrCodeDuplicateFilterSubjects ErrorCode = 10136
  119. JSErrCodeOverlappingFilterSubjects ErrorCode = 10138
  120. JSErrCodeConsumerEmptyFilter ErrorCode = 10139
  121. JSErrCodeMessageNotFound ErrorCode = 10037
  122. JSErrCodeBadRequest ErrorCode = 10003
  123. JSStreamInvalidConfig ErrorCode = 10052
  124. JSErrCodeStreamWrongLastSequence ErrorCode = 10071
  125. )
  126. // APIError is included in all API responses if there was an error.
  127. type APIError struct {
  128. Code int `json:"code"`
  129. ErrorCode ErrorCode `json:"err_code"`
  130. Description string `json:"description,omitempty"`
  131. }
  132. // Error prints the JetStream API error code and description
  133. func (e *APIError) Error() string {
  134. return fmt.Sprintf("nats: %s", e.Description)
  135. }
  136. // APIError implements the JetStreamError interface.
  137. func (e *APIError) APIError() *APIError {
  138. return e
  139. }
  140. // Is matches against an APIError.
  141. func (e *APIError) Is(err error) bool {
  142. if e == nil {
  143. return false
  144. }
  145. // Extract internal APIError to match against.
  146. var aerr *APIError
  147. ok := errors.As(err, &aerr)
  148. if !ok {
  149. return ok
  150. }
  151. return e.ErrorCode == aerr.ErrorCode
  152. }
  153. // JetStreamError is an error result that happens when using JetStream.
  154. // In case of client-side error, `APIError()` returns nil
  155. type JetStreamError interface {
  156. APIError() *APIError
  157. error
  158. }
  159. type jsError struct {
  160. apiErr *APIError
  161. message string
  162. }
  163. func (err *jsError) APIError() *APIError {
  164. return err.apiErr
  165. }
  166. func (err *jsError) Error() string {
  167. if err.apiErr != nil && err.apiErr.Description != "" {
  168. return err.apiErr.Error()
  169. }
  170. return fmt.Sprintf("nats: %s", err.message)
  171. }
  172. func (err *jsError) Unwrap() error {
  173. // Allow matching to embedded APIError in case there is one.
  174. if err.apiErr == nil {
  175. return nil
  176. }
  177. return err.apiErr
  178. }