Track .cursor/rules/ in git so coding conventions are shared across the team. Everything else under .cursor/ stays ignored. Signed-off-by: Émile Ré <emile@probo.com>
47 lines
983 B
Plaintext
47 lines
983 B
Plaintext
---
|
|
description: Go error handling — wrap with fmt.Errorf, always name err, use errors.AsType
|
|
globs: "**/*.go"
|
|
alwaysApply: false
|
|
---
|
|
|
|
# Go error handling
|
|
|
|
## Wrapping
|
|
|
|
- Error variables are always named `err`
|
|
- When a function returns errors from multiple call sites, each must be wrapped
|
|
- Wrap with `fmt.Errorf("cannot ...: %w", err)` — lowercase, starts with `cannot`
|
|
- Each wrap message in a function must be distinct
|
|
|
|
```go
|
|
// GOOD
|
|
foo, err := s.loadFoo(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot load foo: %w", err)
|
|
}
|
|
|
|
bar, err := s.loadBar(ctx, foo.ID)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot load bar: %w", err)
|
|
}
|
|
|
|
// BAD — bare return without wrapping
|
|
foo, err := s.loadFoo(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
```
|
|
|
|
## Type assertions on errors
|
|
|
|
Use `errors.AsType[T](err)` (generic form), not `errors.As(err, &ptr)`:
|
|
|
|
```go
|
|
// GOOD
|
|
if e, ok := errors.AsType[*ValidationError](err); ok { ... }
|
|
|
|
// BAD
|
|
var ve *ValidationError
|
|
if errors.As(err, &ve) { ... }
|
|
```
|