github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/datastore/errors.go (about) 1 package datastore 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/rs/zerolog" 8 ) 9 10 // ErrNotFound is a shared interface for not found errors. 11 type ErrNotFound interface { 12 IsNotFoundError() bool 13 } 14 15 // ErrNamespaceNotFound occurs when a namespace was not found. 16 type ErrNamespaceNotFound struct { 17 error 18 namespaceName string 19 } 20 21 var _ ErrNotFound = ErrNamespaceNotFound{} 22 23 func (err ErrNamespaceNotFound) IsNotFoundError() bool { 24 return true 25 } 26 27 // NotFoundNamespaceName is the name of the namespace not found. 28 func (err ErrNamespaceNotFound) NotFoundNamespaceName() string { 29 return err.namespaceName 30 } 31 32 // MarshalZerologObject implements zerolog object marshalling. 33 func (err ErrNamespaceNotFound) MarshalZerologObject(e *zerolog.Event) { 34 e.Err(err.error).Str("namespace", err.namespaceName) 35 } 36 37 // DetailsMetadata returns the metadata for details for this error. 38 func (err ErrNamespaceNotFound) DetailsMetadata() map[string]string { 39 return map[string]string{ 40 "definition_name": err.namespaceName, 41 } 42 } 43 44 // ErrWatchDisconnected occurs when a watch has fallen too far behind and was forcibly disconnected 45 // as a result. 46 type ErrWatchDisconnected struct{ error } 47 48 // ErrWatchCanceled occurs when a watch was canceled by the caller. 49 type ErrWatchCanceled struct{ error } 50 51 // ErrWatchDisabled occurs when watch is disabled by being unsupported by the datastore. 52 type ErrWatchDisabled struct{ error } 53 54 // ErrReadOnly is returned when the operation cannot be completed because the datastore is in 55 // read-only mode. 56 type ErrReadOnly struct{ error } 57 58 // ErrWatchRetryable is returned when a transient/temporary error occurred in watch and indicates that 59 // the caller *may* retry the watch after some backoff time. 60 type ErrWatchRetryable struct{ error } 61 62 // InvalidRevisionReason is the reason the revision could not be used. 63 type InvalidRevisionReason int 64 65 const ( 66 // RevisionStale is the reason returned when a revision is outside the window of 67 // validity by being too old. 68 RevisionStale InvalidRevisionReason = iota 69 70 // CouldNotDetermineRevision is the reason returned when a revision for a 71 // request could not be determined. 72 CouldNotDetermineRevision 73 ) 74 75 // ErrInvalidRevision occurs when a revision specified to a call was invalid. 76 type ErrInvalidRevision struct { 77 error 78 revision Revision 79 reason InvalidRevisionReason 80 } 81 82 // InvalidRevision is the revision that failed. 83 func (err ErrInvalidRevision) InvalidRevision() Revision { 84 return err.revision 85 } 86 87 // Reason is the reason the revision failed. 88 func (err ErrInvalidRevision) Reason() InvalidRevisionReason { 89 return err.reason 90 } 91 92 // MarshalZerologObject implements zerolog object marshalling. 93 func (err ErrInvalidRevision) MarshalZerologObject(e *zerolog.Event) { 94 switch err.reason { 95 case RevisionStale: 96 e.Err(err.error).Str("reason", "stale") 97 case CouldNotDetermineRevision: 98 e.Err(err.error).Str("reason", "indeterminate") 99 default: 100 e.Err(err.error).Str("reason", "unknown") 101 } 102 } 103 104 // NewNamespaceNotFoundErr constructs a new namespace not found error. 105 func NewNamespaceNotFoundErr(nsName string) error { 106 return ErrNamespaceNotFound{ 107 error: fmt.Errorf("object definition `%s` not found", nsName), 108 namespaceName: nsName, 109 } 110 } 111 112 // NewWatchDisconnectedErr constructs a new watch was disconnected error. 113 func NewWatchDisconnectedErr() error { 114 return ErrWatchDisconnected{ 115 error: fmt.Errorf("watch fell too far behind and was disconnected; consider increasing watch buffer size via the flag --datastore-watch-buffer-length"), 116 } 117 } 118 119 // NewWatchCanceledErr constructs a new watch was canceled error. 120 func NewWatchCanceledErr() error { 121 return ErrWatchCanceled{ 122 error: fmt.Errorf("watch was canceled by the caller"), 123 } 124 } 125 126 // NewWatchDisabledErr constructs a new watch is disabled error. 127 func NewWatchDisabledErr(reason string) error { 128 return ErrWatchDisabled{ 129 error: fmt.Errorf("watch is currently disabled: %s", reason), 130 } 131 } 132 133 // NewWatchTemporaryErr wraps another error in watch, indicating that the error is likely 134 // a temporary condition and clients may consider retrying by calling watch again (vs a fatal error). 135 func NewWatchTemporaryErr(wrapped error) error { 136 return ErrWatchRetryable{ 137 error: fmt.Errorf("watch has failed with a temporary condition: %w. please retry the watch", wrapped), 138 } 139 } 140 141 // NewReadonlyErr constructs an error for when a request has failed because 142 // the datastore has been configured to be read-only. 143 func NewReadonlyErr() error { 144 return ErrReadOnly{ 145 error: fmt.Errorf("datastore is in read-only mode"), 146 } 147 } 148 149 // NewInvalidRevisionErr constructs a new invalid revision error. 150 func NewInvalidRevisionErr(revision Revision, reason InvalidRevisionReason) error { 151 switch reason { 152 case RevisionStale: 153 return ErrInvalidRevision{ 154 error: fmt.Errorf("revision has expired"), 155 revision: revision, 156 reason: reason, 157 } 158 159 default: 160 return ErrInvalidRevision{ 161 error: fmt.Errorf("revision was invalid"), 162 revision: revision, 163 reason: reason, 164 } 165 } 166 } 167 168 // ErrCaveatNameNotFound is the error returned when a caveat is not found by its name 169 type ErrCaveatNameNotFound struct { 170 error 171 name string 172 } 173 174 var _ ErrNotFound = ErrCaveatNameNotFound{} 175 176 func (err ErrCaveatNameNotFound) IsNotFoundError() bool { 177 return true 178 } 179 180 // CaveatName returns the name of the caveat that couldn't be found 181 func (err ErrCaveatNameNotFound) CaveatName() string { 182 return err.name 183 } 184 185 // NewCaveatNameNotFoundErr constructs a new caveat name not found error. 186 func NewCaveatNameNotFoundErr(name string) error { 187 return ErrCaveatNameNotFound{ 188 error: fmt.Errorf("caveat with name `%s` not found", name), 189 name: name, 190 } 191 } 192 193 // DetailsMetadata returns the metadata for details for this error. 194 func (err ErrCaveatNameNotFound) DetailsMetadata() map[string]string { 195 return map[string]string{ 196 "caveat_name": err.name, 197 } 198 } 199 200 var ( 201 ErrClosedIterator = errors.New("unable to iterate: iterator closed") 202 ErrCursorsWithoutSorting = errors.New("cursors are disabled on unsorted results") 203 ErrCursorEmpty = errors.New("cursors are only available after the first result") 204 )