Skip to content

Commit 2cc40ed

Browse files
committed
feat: improved error handling
1 parent f5a1bc6 commit 2cc40ed

26 files changed

Lines changed: 256 additions & 23 deletions

go.mod

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,23 @@ go 1.25.7
44

55
require (
66
github.com/a-h/templ v0.3.1001
7-
github.com/xraph/fabriq v0.0.3
7+
github.com/jackc/pgx/v5 v5.10.0
8+
github.com/xraph/fabriq v0.0.4
89
github.com/xraph/forge v1.8.0
910
github.com/xraph/forgeui v1.4.1
1011
github.com/xraph/go-utils v1.1.1
11-
github.com/xraph/grove v1.5.8
12-
github.com/xraph/grove/drivers/mongodriver v1.5.8
13-
github.com/xraph/grove/drivers/pgdriver v1.5.8
14-
github.com/xraph/grove/drivers/sqlitedriver v1.5.8
12+
github.com/xraph/grove v1.5.9
13+
github.com/xraph/grove/drivers/mongodriver v1.5.9
14+
github.com/xraph/grove/drivers/pgdriver v1.5.9
15+
github.com/xraph/grove/drivers/sqlitedriver v1.5.9
1516
github.com/xraph/nexus v1.5.5
1617
github.com/xraph/sentinel v1.5.2
1718
github.com/xraph/shield v1.5.2
1819
github.com/xraph/vessel v1.0.2
1920
github.com/xraph/weave v1.5.4
2021
go.jetify.com/typeid/v2 v2.0.0-alpha.3
2122
go.mongodb.org/mongo-driver/v2 v2.5.0
23+
modernc.org/sqlite v1.46.1
2224
)
2325

2426
require go.uber.org/atomic v1.11.0 // indirect
@@ -83,7 +85,6 @@ require (
8385
github.com/hashicorp/serf v0.10.1 // indirect
8486
github.com/jackc/pgpassfile v1.0.0 // indirect
8587
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
86-
github.com/jackc/pgx/v5 v5.10.0 // indirect
8788
github.com/jackc/puddle/v2 v2.2.2 // indirect
8889
github.com/josharian/intern v1.0.0 // indirect
8990
github.com/json-iterator/go v1.1.12 // indirect
@@ -141,8 +142,8 @@ require (
141142
github.com/xdg-go/scram v1.2.0 // indirect
142143
github.com/xdg-go/stringprep v1.0.4 // indirect
143144
github.com/xraph/confy v0.5.2 // indirect
144-
github.com/xraph/grove/kv v1.5.7 // indirect
145-
github.com/xraph/grove/kv/drivers/redisdriver v1.5.7 // indirect
145+
github.com/xraph/grove/kv v1.5.8 // indirect
146+
github.com/xraph/grove/kv/drivers/redisdriver v1.5.8 // indirect
146147
github.com/xraph/trove v1.5.1 // indirect
147148
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
148149
github.com/yusufpapurcu/wmi v1.2.4 // indirect
@@ -186,7 +187,6 @@ require (
186187
modernc.org/libc v1.68.0 // indirect
187188
modernc.org/mathutil v1.7.1 // indirect
188189
modernc.org/memory v1.11.0 // indirect
189-
modernc.org/sqlite v1.46.1 // indirect
190190
nhooyr.io/websocket v1.8.17 // indirect
191191
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
192192
sigs.k8s.io/randfill v1.0.0 // indirect

go.sum

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -408,26 +408,26 @@ github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6
408408
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
409409
github.com/xraph/confy v0.5.2 h1:YlZDDG2sZWyiSm4yjXTLQ7RFdy/3izg/plJh1g9guEA=
410410
github.com/xraph/confy v0.5.2/go.mod h1:FPupuOi04fSgh8pKb9BOTPxyzq9WhIncfY9aDH0bLO8=
411-
github.com/xraph/fabriq v0.0.3 h1:RX6sTLvjB5ZmGvuPitJMYa06y0OA+1fCQyKtwXcqejI=
412-
github.com/xraph/fabriq v0.0.3/go.mod h1:mr8mWrSKs4X8lUMHp7rUuiQkrG7sY+PSuQYIWW/5eB0=
411+
github.com/xraph/fabriq v0.0.4 h1:GamTKt+eRIl6Jj1SS/6zLeOFODDm3hK3gnwcBdOHg54=
412+
github.com/xraph/fabriq v0.0.4/go.mod h1:YLX7fHRmgqPqcOz4T+5ek8VSk/i70ltB0IpEYWD6IH4=
413413
github.com/xraph/forge v1.8.0 h1:P+Pw0krcF3L278wiWHTs3KZDaC53j4egKguzOpKr+nA=
414414
github.com/xraph/forge v1.8.0/go.mod h1:a+N9fYEEwb6Los1VcJ9V/xFThohkQsyo7vc9w9mD7V4=
415415
github.com/xraph/forgeui v1.4.1 h1:LHK1t/sZ+9zL+MNUZralO9/rc0f5UCa19dpbWTuRMNg=
416416
github.com/xraph/forgeui v1.4.1/go.mod h1:rH/+wb1tt2pXSHotWAvoP+Lt846xlIjuwPDSpS5K5mw=
417417
github.com/xraph/go-utils v1.1.1 h1:k5TOQ1qhXLdEX8W5F60mSuPcFOPc8sBsnhmjx/Kpr5g=
418418
github.com/xraph/go-utils v1.1.1/go.mod h1:tZN4SuGy9otCo6dETp7Cvkgyiy0BvaJaZbTBv4Euvo4=
419-
github.com/xraph/grove v1.5.8 h1:BgTy8+9V4l5OSqkXmM25mXNxh15FX7GFPjgWNaXjwH0=
420-
github.com/xraph/grove v1.5.8/go.mod h1:bgjHNhnmyfEyzbdpcppRt+Zf24nNcbGKlo450Mi4giI=
421-
github.com/xraph/grove/drivers/mongodriver v1.5.8 h1:RKDD0RnWPSl6WhwIaLf6wiCFXc9mo3rCzDH06NQBPDM=
422-
github.com/xraph/grove/drivers/mongodriver v1.5.8/go.mod h1:xojoSuw3qSm3NIe3xBmasocRQ7oyju3XbjvdlCXVXIU=
423-
github.com/xraph/grove/drivers/pgdriver v1.5.8 h1:p47i96rmhOGDMYT949FbH06k4vRvQ+9rDpXCgNvEl+Q=
424-
github.com/xraph/grove/drivers/pgdriver v1.5.8/go.mod h1:BBCrIuCBrRajE/dB5IKC0HshU/bUHPNS/etWtmX19qo=
425-
github.com/xraph/grove/drivers/sqlitedriver v1.5.8 h1:GpncObiNhFdwWLowt7Xb9vul+vV0xingp6DqKyMvzsQ=
426-
github.com/xraph/grove/drivers/sqlitedriver v1.5.8/go.mod h1:xzHewWROOPVn0Luu8/sWEAhSgmDnw3xmNrRw0xcefnM=
427-
github.com/xraph/grove/kv v1.5.7 h1:kkkicqZdLQkur4K4jKpKQiwq1uRJchTjO5LvWofMKOw=
428-
github.com/xraph/grove/kv v1.5.7/go.mod h1:rdwh/Ja2WOhZ3YwrIp8vBeDNATAOj+2vrK+XVuRHrJU=
429-
github.com/xraph/grove/kv/drivers/redisdriver v1.5.7 h1:XpzswYNxTvbJJ5Pk7gWwl4SGFTI1k3CMC0UfqY7xUHk=
430-
github.com/xraph/grove/kv/drivers/redisdriver v1.5.7/go.mod h1:15TFWsrEvCTHKiqgn40x06VzQTFEaiWyjpVoA2m3FFU=
419+
github.com/xraph/grove v1.5.9 h1:BTYvJnq5zqKWMr2bkDPmW7BWE5HZkThOmWn/qT6C/XE=
420+
github.com/xraph/grove v1.5.9/go.mod h1:bgjHNhnmyfEyzbdpcppRt+Zf24nNcbGKlo450Mi4giI=
421+
github.com/xraph/grove/drivers/mongodriver v1.5.9 h1:KUUzAdAPGgOZfiIgh3Ipekq8/As/j3ZnAK1DmerA5/0=
422+
github.com/xraph/grove/drivers/mongodriver v1.5.9/go.mod h1:xojoSuw3qSm3NIe3xBmasocRQ7oyju3XbjvdlCXVXIU=
423+
github.com/xraph/grove/drivers/pgdriver v1.5.9 h1:HOnF6RjWA9p4WkKL/xHJqUzVq/MZoIlARYkD/dvcUdw=
424+
github.com/xraph/grove/drivers/pgdriver v1.5.9/go.mod h1:BBCrIuCBrRajE/dB5IKC0HshU/bUHPNS/etWtmX19qo=
425+
github.com/xraph/grove/drivers/sqlitedriver v1.5.9 h1:vtpkXh5NUWI1X9/UUkA5PF1oVLbd9LkPXtQPy3gmOwM=
426+
github.com/xraph/grove/drivers/sqlitedriver v1.5.9/go.mod h1:xzHewWROOPVn0Luu8/sWEAhSgmDnw3xmNrRw0xcefnM=
427+
github.com/xraph/grove/kv v1.5.8 h1:Eg+laumIvqa/pQxCpxsqX2QPXQHdpJGlGfRMaHwbrcM=
428+
github.com/xraph/grove/kv v1.5.8/go.mod h1:rdwh/Ja2WOhZ3YwrIp8vBeDNATAOj+2vrK+XVuRHrJU=
429+
github.com/xraph/grove/kv/drivers/redisdriver v1.5.8 h1:Glz3AJMB2D2U8Qco13ciLfh5LJWCcAW5nh46xvs5w+o=
430+
github.com/xraph/grove/kv/drivers/redisdriver v1.5.8/go.mod h1:15TFWsrEvCTHKiqgn40x06VzQTFEaiWyjpVoA2m3FFU=
431431
github.com/xraph/nexus v1.5.5 h1:ccxqPpJ+z/5UImdYkOBwgov6Qo5lQYEhOtcjeDPOr8Q=
432432
github.com/xraph/nexus v1.5.5/go.mod h1:Qug6QyTrXIeD0oMPO0vVvMcF8jNZiZ+oqn9YuRdg8HI=
433433
github.com/xraph/sentinel v1.5.2 h1:cxSI6PZ49uUKj6egaCFtwTrAwrKtgeeBvY4yG+xPbEA=

store/mongo/agent.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ func (s *Store) Create(ctx context.Context, config *agent.Config) error {
2020

2121
_, err := s.mdb.NewInsert(m).Exec(ctx)
2222
if err != nil {
23+
if isUniqueViolation(err) {
24+
return fmt.Errorf("cortex/mongo: create agent: %w", cortex.ErrAlreadyExists)
25+
}
2326
return fmt.Errorf("cortex/mongo: create agent: %w", err)
2427
}
2528

store/mongo/behavior.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ func (s *Store) CreateBehavior(ctx context.Context, b *behavior.Behavior) error
2020

2121
_, err := s.mdb.NewInsert(m).Exec(ctx)
2222
if err != nil {
23+
if isUniqueViolation(err) {
24+
return fmt.Errorf("cortex/mongo: create behavior: %w", cortex.ErrAlreadyExists)
25+
}
2326
return fmt.Errorf("cortex/mongo: create behavior: %w", err)
2427
}
2528

store/mongo/orchestration.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ func (s *Store) CreateOrchestration(ctx context.Context, c *orchestration.Config
1818
c.UpdatedAt = t
1919

2020
if _, err := s.mdb.NewInsert(orchestrationConfigToModel(c)).Exec(ctx); err != nil {
21+
if isUniqueViolation(err) {
22+
return fmt.Errorf("cortex/mongo: create orchestration: %w", cortex.ErrAlreadyExists)
23+
}
2124
return fmt.Errorf("cortex/mongo: create orchestration: %w", err)
2225
}
2326

store/mongo/persona.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ func (s *Store) CreatePersona(ctx context.Context, p *persona.Persona) error {
2020

2121
_, err := s.mdb.NewInsert(m).Exec(ctx)
2222
if err != nil {
23+
if isUniqueViolation(err) {
24+
return fmt.Errorf("cortex/mongo: create persona: %w", cortex.ErrAlreadyExists)
25+
}
2326
return fmt.Errorf("cortex/mongo: create persona: %w", err)
2427
}
2528

store/mongo/skill.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ func (s *Store) CreateSkill(ctx context.Context, sk *skill.Skill) error {
2020

2121
_, err := s.mdb.NewInsert(m).Exec(ctx)
2222
if err != nil {
23+
if isUniqueViolation(err) {
24+
return fmt.Errorf("cortex/mongo: create skill: %w", cortex.ErrAlreadyExists)
25+
}
2326
return fmt.Errorf("cortex/mongo: create skill: %w", err)
2427
}
2528

store/mongo/store.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,9 @@ func now() time.Time {
8484
func isNoDocuments(err error) bool {
8585
return errors.Is(err, mongo.ErrNoDocuments)
8686
}
87+
88+
// isUniqueViolation reports whether err is a MongoDB duplicate-key error
89+
// (code 11000), so callers can translate it into cortex.ErrAlreadyExists.
90+
func isUniqueViolation(err error) bool {
91+
return mongo.IsDuplicateKeyError(err)
92+
}

store/mongo/store_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package mongo
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"testing"
7+
8+
"go.mongodb.org/mongo-driver/v2/mongo"
9+
)
10+
11+
func TestIsUniqueViolation(t *testing.T) {
12+
dup := mongo.WriteException{
13+
WriteErrors: mongo.WriteErrors{{Code: 11000, Message: "E11000 duplicate key error"}},
14+
}
15+
tests := []struct {
16+
name string
17+
err error
18+
want bool
19+
}{
20+
{"nil", nil, false},
21+
{"duplicate key", dup, true},
22+
{"wrapped duplicate key", fmt.Errorf("create agent: %w", dup), true},
23+
{"plain error", errors.New("boom"), false},
24+
}
25+
for _, tt := range tests {
26+
t.Run(tt.name, func(t *testing.T) {
27+
if got := isUniqueViolation(tt.err); got != tt.want {
28+
t.Errorf("isUniqueViolation(%v) = %v, want %v", tt.err, got, tt.want)
29+
}
30+
})
31+
}
32+
}

store/mongo/trait.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ func (s *Store) CreateTrait(ctx context.Context, t *trait.Trait) error {
2020

2121
_, err := s.mdb.NewInsert(m).Exec(ctx)
2222
if err != nil {
23+
if isUniqueViolation(err) {
24+
return fmt.Errorf("cortex/mongo: create trait: %w", cortex.ErrAlreadyExists)
25+
}
2326
return fmt.Errorf("cortex/mongo: create trait: %w", err)
2427
}
2528

0 commit comments

Comments
 (0)