Skip to content
This repository was archived by the owner on Dec 6, 2025. It is now read-only.

Commit 7a6256a

Browse files
authored
chore: err113 (#906)
1 parent 89e2023 commit 7a6256a

File tree

45 files changed

+488
-174
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+488
-174
lines changed

.golangci.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ linters:
2828
# TODOs: #865
2929
- cyclop # TODO
3030
- dupl # TODO
31-
- err113 # TODO
3231
- exhaustruct # TODO
3332
- gci # TODO
3433
- gocognit # TODO

libs/common/hwerr/err.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package hwerr
22

33
import (
44
"context"
5+
"fmt"
56
"hwlocale"
67

78
zlog "github.com/rs/zerolog"
89
"google.golang.org/genproto/googleapis/rpc/errdetails"
10+
genstatus "google.golang.org/genproto/googleapis/rpc/status"
911
"google.golang.org/grpc/codes"
1012
"google.golang.org/grpc/status"
1113
"google.golang.org/protobuf/protoadapt"
@@ -54,3 +56,27 @@ func LocalizedMessage(ctx context.Context, locale hwlocale.Locale) *errdetails.L
5456
Message: str,
5557
}
5658
}
59+
60+
type InvalidEnumError struct {
61+
Enum string
62+
Value string
63+
}
64+
65+
func (e InvalidEnumError) Error() string {
66+
return fmt.Sprintf("invalid enum: %q is not a valid %q", e.Value, e.Enum)
67+
}
68+
69+
// ProtoStatusError implements the Error interface on *genstatus.Status
70+
type ProtoStatusError struct {
71+
status *genstatus.Status
72+
}
73+
74+
func (e ProtoStatusError) Error() string {
75+
return e.status.GetMessage()
76+
}
77+
78+
func NewProtoStatusError(status *genstatus.Status) ProtoStatusError {
79+
return ProtoStatusError{
80+
status: status,
81+
}
82+
}

libs/common/hwgrpc/auth_interceptor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func authInterceptor(ctx context.Context) (context.Context, error) {
6363
Msg("only fake auth is enabled! no attempt verifying token. falling back to fake token instead")
6464
claims, tokenExpires, err = auth.VerifyFakeToken(ctx, token)
6565
} else {
66-
// verify token -> if fakeToken is used claims will be nil and we will get an error
66+
// verify token -> if fakeToken is used claims will be nil, and we will get an error
6767
claims, tokenExpires, err = auth.VerifyIDToken(ctx, token)
6868
}
6969

libs/common/hwgrpc/organization_interceptor.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ func StreamOrganizationInterceptor(
4949
return next(req, stream)
5050
}
5151

52+
var ErrOrganizationIdMissing = errors.New("organization.id missing in id token")
53+
5254
// organizationInterceptor parses and injects the organization id of the OIDC claims into the current context
5355
// This is a separate function to allow endpoints to not fail when an organization id is not provided
5456
func organizationInterceptor(ctx context.Context) (context.Context, error) {
@@ -61,7 +63,7 @@ func organizationInterceptor(ctx context.Context) (context.Context, error) {
6163
}
6264

6365
if len(claims.Organization.Id) == 0 {
64-
return nil, errors.New("organization.id missing in id token")
66+
return nil, ErrOrganizationIdMissing
6567
}
6668

6769
// parse organizationID

libs/common/otel.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ func newTraceProvider(ctx context.Context, res *resource.Resource) (*trace.Trace
128128
return traceProvider, nil
129129
}
130130

131+
var ErrOtelTraceExporterInvalid = errors.New("OTEL_TRACE_EXPORTER invalid")
132+
131133
// newTraceExporter returns a new trace.SpanExporter based on the OTEL_TRACE_EXPORTER env variable
132134
// A SpanExporter pushes traces to a tracing database. For more configuration see the corresponding documentation.
133135
func newTraceExporter(ctx context.Context) (trace.SpanExporter, error) {
@@ -145,6 +147,6 @@ func newTraceExporter(ctx context.Context) (trace.SpanExporter, error) {
145147
// more info: https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace/[email protected]
146148
return otlptracehttp.New(ctx)
147149
default:
148-
return nil, errors.New("OTEL_TRACE_EXPORTER invalid")
150+
return nil, ErrOtelTraceExporterInvalid
149151
}
150152
}

libs/hwauthz/spicedb/spicedb.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package spicedb
22

33
import (
4+
"common/hwerr"
45
"context"
56
"errors"
67
"fmt"
@@ -217,7 +218,7 @@ func (s *SpiceDBAuthZ) BulkCheck(ctx context.Context, checks []hwauthz.Permissio
217218
resc := req.GetResource()
218219

219220
if pberr := pair.GetError(); pberr != nil {
220-
err := fmt.Errorf("spicedb: error while checking permissions: %s", pberr.GetMessage())
221+
err := fmt.Errorf("spicedb: error while checking permissions: %w", hwerr.NewProtoStatusError(pberr))
221222
log.Error().Err(err).Msg("spicedb: error while checking permissions")
222223
return nil, err
223224
}

libs/hwdb/errors.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import (
44
"common/hwerr"
55
"context"
66
"errors"
7+
"fmt"
78
"hwlocale"
89
"reflect"
910
"strings"
1011
"telemetry"
1112

13+
"github.com/google/uuid"
14+
1215
"github.com/jackc/pgerrcode"
1316
"github.com/jackc/pgx/v5/pgconn"
1417
"github.com/rs/zerolog"
@@ -261,3 +264,9 @@ func pgConnErr(ctx context.Context, connErr *pgconn.ConnectError) error {
261264
Msg("connection issue")
262265
return genericStatusError(ctx, "database connection issue")
263266
}
267+
268+
type RecordNotFoundError uuid.UUID
269+
270+
func (e RecordNotFoundError) Error() string {
271+
return fmt.Sprintf("could not find record with id %q", uuid.UUID(e).String())
272+
}

libs/hwes/aggregate.go

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ func (a *AggregateBase) RegisterEventListener(eventType string, eventHandler eve
121121
return a
122122
}
123123

124+
type EventTypeInvalidError string
125+
126+
func (e EventTypeInvalidError) Error() string {
127+
return fmt.Sprintf("event type '%s' is invalid", string(e))
128+
}
129+
124130
// HandleEvent finds and calls the registered event handler
125131
// based on the type of the passed event.
126132
// The executed event handler can modify the in-memory data of the aggregate.
@@ -133,7 +139,7 @@ func (a *AggregateBase) HandleEvent(event Event) error {
133139

134140
eventHandler, found := a.eventHandlers[event.EventType]
135141
if !found {
136-
return fmt.Errorf("event type '%s' is invalid", event.EventType)
142+
return EventTypeInvalidError(event.EventType)
137143
}
138144

139145
if err := eventHandler(event); err != nil {
@@ -155,13 +161,27 @@ func (a *AggregateBase) ClearUncommittedEvents() {
155161
a.uncommittedEvents = make([]Event, 0)
156162
}
157163

164+
type EventAggregateMismatchError struct {
165+
Targeted uuid.UUID
166+
Got uuid.UUID
167+
}
168+
169+
func (e EventAggregateMismatchError) Error() string {
170+
return fmt.Sprintf("event applied to aggregate %q but was targeted at aggregate %q",
171+
e.Got.String(), e.Targeted.String())
172+
}
173+
174+
var ErrLoadDeletedAggregate = errors.New("AggregateBase.Load: aggregate has been marked as deleted")
175+
158176
// Load applies events to an aggregate by utilizing the registered event listeners
159177
// Currently not in use. Could be helpful for testing.
160178
func (a *AggregateBase) Load(events []Event) error {
161179
for _, event := range events {
162180
if event.GetAggregateID() != a.GetID() {
163-
return fmt.Errorf("event applied to aggregate '%s' but was targeted at aggregate '%s'",
164-
a.GetID(), event.GetAggregateID())
181+
return fmt.Errorf("AggregateBase.Load: %w", EventAggregateMismatchError{
182+
Targeted: a.GetID(),
183+
Got: event.GetAggregateID(),
184+
})
165185
}
166186

167187
if err := a.HandleEvent(event); err != nil {
@@ -172,7 +192,7 @@ func (a *AggregateBase) Load(events []Event) error {
172192
a.version++
173193
}
174194
if a.IsDeleted() {
175-
return errors.New("AggregateBase.Load: aggregate has been marked as deleted")
195+
return fmt.Errorf("AggregateBase.Load: %w", ErrLoadDeletedAggregate)
176196
}
177197

178198
return nil
@@ -183,8 +203,10 @@ func (a *AggregateBase) Load(events []Event) error {
183203
// Apply -> You apply a *new* event to the aggregate that could be persisted
184204
func (a *AggregateBase) Apply(event Event) error {
185205
if event.GetAggregateID() != a.GetID() {
186-
return fmt.Errorf("event applied to aggregate '%s' but was targeted at aggregate '%s'",
187-
a.GetID(), event.GetAggregateID())
206+
return fmt.Errorf("AggregateBase.Apply: %w", EventAggregateMismatchError{
207+
Targeted: a.GetID(),
208+
Got: event.GetAggregateID(),
209+
})
188210
}
189211

190212
if err := a.HandleEvent(event); err != nil {
@@ -197,18 +219,29 @@ func (a *AggregateBase) Apply(event Event) error {
197219
return nil
198220
}
199221

222+
type EventOutOfDateError struct {
223+
AggregateVersion uint64
224+
EventVersion uint64
225+
}
226+
227+
func (e EventOutOfDateError) Error() string {
228+
return fmt.Sprintf("event version (%d) is lower than aggregate version (%d)",
229+
e.EventVersion, e.AggregateVersion)
230+
}
231+
200232
// Progress should be called after all events are loaded though an aggregate store.
201233
// The passed event gets applied to an aggregate by utilizing the registered event listeners.
202234
// Progress -> You progress the state of an aggregate
203235
func (a *AggregateBase) Progress(event Event) error {
204236
if event.GetAggregateID() != a.GetID() {
205-
return fmt.Errorf("event applied to aggregate '%s' but was targeted at aggregate '%s'",
206-
a.GetID(), event.GetAggregateID())
237+
return fmt.Errorf("AggregateBase.Progress: %w", EventAggregateMismatchError{
238+
Targeted: a.GetID(),
239+
Got: event.GetAggregateID(),
240+
})
207241
}
208242

209243
if event.GetVersion() < a.GetVersion() {
210-
return fmt.Errorf("event version of %d is lower then aggregate version of %d",
211-
event.GetVersion(), a.GetVersion())
244+
return EventOutOfDateError{EventVersion: event.GetVersion(), AggregateVersion: a.GetVersion()}
212245
}
213246

214247
if err := a.HandleEvent(event); err != nil {

libs/hwes/errs/errors.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package errs
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/google/uuid"
8+
)
9+
10+
var (
11+
ErrAlreadyExists = errors.New("cannot create an already existing aggregate")
12+
ErrOrganizationMissing = errors.New("organization is missing from event")
13+
ErrCommitterMissing = errors.New("committer is missing from event")
14+
ErrPayloadMissing = errors.New("payload is empty")
15+
)
16+
17+
type NotFoundError uuid.UUID
18+
19+
func (e NotFoundError) Error() string {
20+
return fmt.Sprintf("record with id %s not found", uuid.UUID(e).String())
21+
}

libs/hwes/event.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"errors"
88
"fmt"
99
"hwutil"
10+
"hwutil/errs"
1011
"strings"
1112
"telemetry"
1213
"time"
@@ -70,13 +71,16 @@ type metadata struct {
7071
func GetEventTypeOptionOfProtoMessageV1(protoMessage proto.Message) string {
7172
eventTypeOption := pbEventsV1.E_EventType
7273

73-
protoEventType, ok := proto.GetExtension(protoMessage.ProtoReflect().Descriptor().Options(), eventTypeOption).(string)
74+
descriptorOptions := protoMessage.ProtoReflect().Descriptor().Options()
75+
protoEventTypeAny := proto.GetExtension(descriptorOptions, eventTypeOption)
76+
protoEventType, ok := protoEventTypeAny.(string)
7477
if !ok {
75-
panic(fmt.Sprintf(
76-
"String type assertion for eventType '%s' on protoMessage '%s' failed.",
77-
eventTypeOption.TypeDescriptor().FullName(),
78-
protoMessage.ProtoReflect().Descriptor().FullName(),
79-
))
78+
panic(
79+
fmt.Errorf("not a string: eventType %q on protoMessage %q: %w",
80+
eventTypeOption.TypeDescriptor().FullName(),
81+
protoMessage.ProtoReflect().Descriptor().FullName(),
82+
errs.NewCastError("string", protoEventTypeAny)),
83+
)
8084
}
8185

8286
if protoEventType == "" {
@@ -164,6 +168,12 @@ func NewEventFromProto(aggregate Aggregate, message proto.Message, opts ...Event
164168
return event, nil
165169
}
166170

171+
type StreamIdMalformedError string
172+
173+
func (e StreamIdMalformedError) Error() string {
174+
return fmt.Sprintf("cannot resolve aggregateType and aggregateID from streamID %q", string(e))
175+
}
176+
167177
// resolveAggregateIDAndTypeFromStreamID extracts the aggregateID and aggregateType of a given streamID
168178
// See aggregate.GetTypeID
169179
//
@@ -181,13 +191,13 @@ func resolveAggregateIDAndTypeFromStreamID(streamID string) (aID uuid.UUID, aggr
181191
aggregateTypeStr = streamIDParts[0]
182192
aggregateIDStr = streamIDParts[1]
183193
} else {
184-
err = fmt.Errorf("cannot resolve aggregateType and aggregateID from streamID '%s'", streamID)
194+
err = StreamIdMalformedError(streamID)
185195
return
186196
}
187197

188198
aggregateType = AggregateType(aggregateTypeStr)
189199
if aggregateType == "" {
190-
err = fmt.Errorf("resolved empty aggregateType from streamID '%s'", streamID)
200+
err = StreamIdMalformedError(streamID)
191201
return
192202
}
193203

@@ -326,9 +336,11 @@ func (e *Event) SetProtoData(message proto.Message) error {
326336
return nil
327337
}
328338

339+
var ErrGetJsonOnProtoData = errors.New("data of event is marked as proto, use GetProtoData instead")
340+
329341
func (e *Event) GetJsonData(data interface{}) error {
330342
if e.DataIsProto {
331-
return errors.New("data of this event is marked as proto, use GetProtoData instead")
343+
return ErrGetJsonOnProtoData
332344
}
333345

334346
if jsonable, ok := data.(hwutil.JSONAble); ok {
@@ -337,9 +349,11 @@ func (e *Event) GetJsonData(data interface{}) error {
337349
return json.Unmarshal(e.Data, data)
338350
}
339351

352+
var ErrGetProtoOnJsonData = errors.New("data of event is not marked as proto, use GetJsonData instead")
353+
340354
func (e *Event) GetProtoData(message proto.Message) error {
341355
if !e.DataIsProto {
342-
return errors.New("data of this event is not marked as proto, use GetJsonData instead")
356+
return ErrGetProtoOnJsonData
343357
}
344358

345359
return protojson.Unmarshal(e.Data, message)

0 commit comments

Comments
 (0)