goerr-error-handling

star 125

Write Go error handling code using the goerr library. Use when creating errors, wrapping errors, adding context, or handling errors in Go code that uses goerr.

secmon-lab By secmon-lab schedule Updated 2/1/2026

name: goerr-error-handling description: Write Go error handling code using the goerr library. Use when creating errors, wrapping errors, adding context, or handling errors in Go code that uses goerr. allowed-tools: Read, Bash(go:*)

Error Handling with goerr

When writing Go error handling code, use the goerr library for enhanced errors with stack traces, contextual values, and structured logging support.

Step 1: Locate goerr documentation

First, find where goerr is installed and read its documentation:

GOERR_DIR=$(go list -m -f '{{.Dir}}' github.com/m-mizutani/goerr/v2 2>/dev/null)

If goerr is available, read the relevant documentation from $GOERR_DIR/:

  • README.md - Full feature overview, code examples, and API reference
  • docs/migration.md - Migration guide from pkg/errors, standard errors, or goerr v1
  • examples/ - Working example programs for each feature

Step 2: Choose the right function

Situation Use NOT
Create a new error goerr.New("msg") errors.New("msg") or fmt.Errorf("msg")
Wrap an existing error goerr.Wrap(err, "msg") fmt.Errorf("msg: %w", err)
Add context without changing message goerr.With(err, goerr.V("k", v)) goerr.Wrap(err, err.Error(), goerr.V("k", v))
Simple key-value context goerr.V("key", value) Building context into message string
Type-safe context goerr.TV(typedKey, value) goerr.V() when type safety matters
Categorize errors goerr.T(tagValue) Sentinel errors for categories
Shared context across errors goerr.NewBuilder(opts...) Repeating same options everywhere
Collect multiple errors goerr.Append(errs, err) Manual slice management
Define sentinel errors goerr.New("msg", goerr.ID("ERR_X")) errors.New("msg")
Extract goerr.Error goerr.Unwrap(err) errors.As(err, &goErr)
Extract goerr.Errors goerr.AsErrors(err) errors.As(err, &goErrs)
Check error tag goerr.HasTag(err, tag) Manual unwrap + check

Step 3: Apply best practices

Error messages should describe what failed, not why

// Good
goerr.Wrap(err, "failed to save user")

// Bad - "why" belongs in context values
goerr.Wrap(err, fmt.Sprintf("failed to save user %s due to timeout", userID))

Use context values for structured data, not string interpolation

// Good
goerr.Wrap(err, "query failed",
    goerr.V("table", "users"),
    goerr.V("user_id", userID))

// Bad
goerr.Wrap(err, fmt.Sprintf("query on table users failed for user %s", userID))

Define typed keys at package level for critical values

var (
    UserIDKey = goerr.NewTypedKey[string]("user_id")
    CountKey  = goerr.NewTypedKey[int]("count")
)

err := goerr.New("error", goerr.TV(UserIDKey, "user123"))
if userID, ok := goerr.GetTypedValue(err, UserIDKey); ok {
    // userID is guaranteed to be string
}

Define tags and sentinel errors at package level

var (
    TagNotFound   = goerr.NewTag("not_found")
    TagValidation = goerr.NewTag("validation")
)

var (
    ErrNotFound = goerr.New("not found", goerr.ID("ERR_NOT_FOUND"))
    ErrInvalid  = goerr.New("invalid input", goerr.ID("ERR_INVALID"))
)

Use Builder for shared context in a scope

func (s *Service) process() error {
    eb := goerr.NewBuilder(
        goerr.V("user_id", s.userID),
        goerr.V("request_id", s.reqID))

    if err := s.validate(); err != nil {
        return eb.Wrap(err, "validation failed")
    }
    if err := s.save(); err != nil {
        return eb.Wrap(err, "save failed")
    }
    return nil
}

Use Unstack() for helper functions

func newDomainError(msg string, opts ...goerr.Option) *goerr.Error {
    return goerr.New(msg, opts...).Unstack()
}

Use slog integration for structured logging

logger.Error("operation failed", slog.Any("error", err))
// Automatically includes message, values, tags, and stack trace

Quick Reference

Error creation: goerr.New, goerr.Wrap, goerr.With

Options: goerr.Value / goerr.V, goerr.TypedValue / goerr.TV, goerr.Tag / goerr.T, goerr.ID

Extraction: goerr.Unwrap, goerr.AsErrors, goerr.Values, goerr.TypedValues, goerr.Tags, goerr.HasTag, goerr.GetTypedValue

Multiple errors: goerr.Join, goerr.Append, (*Errors).ErrorOrNil, (*Errors).IsEmpty, (*Errors).Len

Builder: goerr.NewBuilder, (*Builder).With, (*Builder).New, (*Builder).Wrap

Type-safe keys: goerr.NewTypedKey[T], goerr.TV, goerr.GetTypedValue

Tags: goerr.NewTag, goerr.T, goerr.HasTag, (*Error).HasTag

Stack control: (*Error).Unstack, (*Error).UnstackN

Install via CLI
npx skills add https://github.com/secmon-lab/warren --skill goerr-error-handling
Repository Details
star Stars 125
call_split Forks 6
navigation Branch main
article Path SKILL.md
More from Creator