github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/graph/errors.go (about) 1 package graph 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/rs/zerolog" 8 "google.golang.org/grpc/codes" 9 "google.golang.org/grpc/status" 10 11 v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" 12 13 "github.com/authzed/spicedb/internal/sharederrors" 14 dispatch "github.com/authzed/spicedb/pkg/proto/dispatch/v1" 15 "github.com/authzed/spicedb/pkg/spiceerrors" 16 ) 17 18 // ErrCheckFailure occurs when check failed in some manner. Note this should not apply to 19 // namespaces and relations not being found. 20 type ErrCheckFailure struct { 21 error 22 } 23 24 func (e ErrCheckFailure) Unwrap() error { 25 return e.error 26 } 27 28 // NewCheckFailureErr constructs a new check failed error. 29 func NewCheckFailureErr(baseErr error) error { 30 return ErrCheckFailure{ 31 error: fmt.Errorf("error performing check: %w", baseErr), 32 } 33 } 34 35 // ErrExpansionFailure occurs when expansion failed in some manner. Note this should not apply to 36 // namespaces and relations not being found. 37 type ErrExpansionFailure struct { 38 error 39 } 40 41 func (e ErrExpansionFailure) Unwrap() error { 42 return e.error 43 } 44 45 // NewExpansionFailureErr constructs a new expansion failed error. 46 func NewExpansionFailureErr(baseErr error) error { 47 return ErrExpansionFailure{ 48 error: fmt.Errorf("error performing expand: %w", baseErr), 49 } 50 } 51 52 // ErrAlwaysFail is returned when an internal error leads to an operation 53 // guaranteed to fail. 54 type ErrAlwaysFail struct { 55 error 56 } 57 58 // NewAlwaysFailErr constructs a new always fail error. 59 func NewAlwaysFailErr() error { 60 return ErrAlwaysFail{ 61 error: errors.New("always fail"), 62 } 63 } 64 65 // ErrRelationNotFound occurs when a relation was not found under a namespace. 66 type ErrRelationNotFound struct { 67 error 68 namespaceName string 69 relationName string 70 } 71 72 // NamespaceName returns the name of the namespace in which the relation was not found. 73 func (err ErrRelationNotFound) NamespaceName() string { 74 return err.namespaceName 75 } 76 77 // NotFoundRelationName returns the name of the relation not found. 78 func (err ErrRelationNotFound) NotFoundRelationName() string { 79 return err.relationName 80 } 81 82 func (err ErrRelationNotFound) MarshalZerologObject(e *zerolog.Event) { 83 e.Err(err.error).Str("namespace", err.namespaceName).Str("relation", err.relationName) 84 } 85 86 // DetailsMetadata returns the metadata for details for this error. 87 func (err ErrRelationNotFound) DetailsMetadata() map[string]string { 88 return map[string]string{ 89 "definition_name": err.namespaceName, 90 "relation_or_permission_name": err.relationName, 91 } 92 } 93 94 // NewRelationNotFoundErr constructs a new relation not found error. 95 func NewRelationNotFoundErr(nsName string, relationName string) error { 96 return ErrRelationNotFound{ 97 error: fmt.Errorf("relation/permission `%s` not found under definition `%s`", relationName, nsName), 98 namespaceName: nsName, 99 relationName: relationName, 100 } 101 } 102 103 var _ sharederrors.UnknownRelationError = ErrRelationNotFound{} 104 105 // ErrRelationMissingTypeInfo defines an error for when type information is missing from a relation 106 // during a lookup. 107 type ErrRelationMissingTypeInfo struct { 108 error 109 namespaceName string 110 relationName string 111 } 112 113 // NamespaceName returns the name of the namespace in which the relation was found. 114 func (err ErrRelationMissingTypeInfo) NamespaceName() string { 115 return err.namespaceName 116 } 117 118 // RelationName returns the name of the relation missing type information. 119 func (err ErrRelationMissingTypeInfo) RelationName() string { 120 return err.relationName 121 } 122 123 func (err ErrRelationMissingTypeInfo) MarshalZerologObject(e *zerolog.Event) { 124 e.Err(err.error).Str("namespace", err.namespaceName).Str("relation", err.relationName) 125 } 126 127 // DetailsMetadata returns the metadata for details for this error. 128 func (err ErrRelationMissingTypeInfo) DetailsMetadata() map[string]string { 129 return map[string]string{ 130 "definition_name": err.namespaceName, 131 "relation_name": err.relationName, 132 } 133 } 134 135 // NewRelationMissingTypeInfoErr constructs a new relation not missing type information error. 136 func NewRelationMissingTypeInfoErr(nsName string, relationName string) error { 137 return ErrRelationMissingTypeInfo{ 138 error: fmt.Errorf("relation/permission `%s` under definition `%s` is missing type information", relationName, nsName), 139 namespaceName: nsName, 140 relationName: relationName, 141 } 142 } 143 144 // ErrInvalidArgument occurs when a request sent has an invalid argument. 145 type ErrInvalidArgument struct { 146 error 147 } 148 149 // NewErrInvalidArgument constructs a request sent has an invalid argument. 150 func NewErrInvalidArgument(baseErr error) error { 151 return ErrInvalidArgument{ 152 error: baseErr, 153 } 154 } 155 156 func (e ErrInvalidArgument) Unwrap() error { 157 return e.error 158 } 159 160 // ErrUnimplemented is returned when some functionality is not yet supported. 161 type ErrUnimplemented struct { 162 error 163 } 164 165 // NewUnimplementedErr constructs a new unimplemented error. 166 func NewUnimplementedErr(baseErr error) error { 167 return ErrUnimplemented{ 168 error: baseErr, 169 } 170 } 171 172 func (e ErrUnimplemented) Unwrap() error { 173 return e.error 174 } 175 176 // ErrInvalidCursor is returned when a cursor is no longer valid. 177 type ErrInvalidCursor struct { 178 error 179 } 180 181 // NewInvalidCursorErr constructs a new unimplemented error. 182 func NewInvalidCursorErr(dispatchCursorVersion uint32, cursor *dispatch.Cursor) error { 183 return ErrInvalidCursor{ 184 error: fmt.Errorf("the supplied cursor is no longer valid: found version %d, expected version %d", cursor.DispatchVersion, dispatchCursorVersion), 185 } 186 } 187 188 // GRPCStatus implements retrieving the gRPC status for the error. 189 func (err ErrInvalidCursor) GRPCStatus() *status.Status { 190 return spiceerrors.WithCodeAndDetails( 191 err, 192 codes.InvalidArgument, 193 spiceerrors.ForReason( 194 v1.ErrorReason_ERROR_REASON_INVALID_CURSOR, 195 map[string]string{ 196 "details": "cursor was used against an incompatible version of SpiceDB", 197 }, 198 ), 199 ) 200 }