affaan-m/ECC · error

get user %s: %w

Error message

get user %s: %w

What it means

Wrapped error from the GetUser example in golang-patterns. GetUser delegates to db.FindUser(id) and, on any non-nil return, wraps it as fmt.Errorf("get user %s: %w", id, err). This is shown as the 'clear and direct' style: a single early-return that preserves the cause via %w and adds the id as context. The message surfaces whenever the underlying lookup fails for any reason.

Source

Thrown at skills/golang-patterns/SKILL.md:30

## When to Activate

- Writing new Go code
- Reviewing Go code
- Refactoring existing Go code
- Designing Go packages/modules

## Core Principles

### 1. Simplicity and Clarity

Go favors simplicity over cleverness. Code should be obvious and easy to read.

```go
// Good: Clear and direct
func GetUser(id string) (*User, error) {
    user, err := db.FindUser(id)
    if err != nil {
        return nil, fmt.Errorf("get user %s: %w", id, err)
    }
    return user, nil
}

// Bad: Overly clever
func GetUser(id string) (*User, error) {
    return func() (*User, error) {
        if u, e := db.FindUser(id); e == nil {
            return u, nil
        } else {
            return nil, e
        }
    }()
}
```

### 2. Make the Zero Value Useful

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Inspect with errors.Is against the store's sentinel errors (e.g. ErrNotFound) to decide between 404 and 500.
  2. Validate the id (non-empty, correct shape) before calling FindUser to surface input errors earlier.
  3. Confirm the data layer connectivity and that FindUser's contract still matches caller assumptions.
  4. Add structured logging of the wrapped cause at the boundary so users see a generic message but operators see detail.

Example fix

// before
user, err := GetUser(id)
if err != nil {
    return err
}

// after
user, err := GetUser(id)
switch {
case errors.Is(err, ErrNotFound):
    return NotFoundResponse(id)
case err != nil:
    log.Printf("get user %s failed: %v", id, err)
    return InternalErrorResponse()
}
Defensive patterns

Strategy: try-catch

Validate before calling

func validateUserID(id string) error {
    if strings.TrimSpace(id) == "" {
        return errors.New("id required")
    }
    return nil
}

Type guard

// Distinguish 'not found' from 'transient failure' for the caller.
func isNotFound(err error) bool {
    return errors.Is(err, ErrNotFound) || errors.Is(err, sql.ErrNoRows)
}

Try / catch

user, err := GetUser(id)
switch {
case isNotFound(err):
    return NotFoundResponse(id)
case err != nil:
    log.Printf("get user %s: %v", id, err)
    return InternalErrorResponse()
}

Prevention

When it happens

Trigger: Calling GetUser(id) when db.FindUser returns a non-nil error. This includes not-found, validation of the id, transport errors to the store, or any failure inside FindUser that is propagated up rather than swallowed.

Common situations: Repository returns a sentinel not-found; id format is invalid and the store rejects it; the data layer is temporarily unavailable; a refactor changed FindUser's error semantics and the caller now bubbles an unexpected cause.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/5329c7488e745b0e. Report an issue: GitHub.