go-error-handling — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited go-error-handling (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
In Go, errors are values — they are created by code and consumed by code.
%v to avoid leaking internals%wfmt.Errorf("...: %w", err)Default: wrap with %w and place it at the end of the format string.
err.Error(), bare return err without context, and log-and-return violations. Run bash scripts/check-errors.sh --help for options.Never return concrete error types from exported functions — a concrete nil pointer can become a non-nil interface:
// Bad: Concrete type can cause subtle bugs
func Bad() *os.PathError { /*...*/ }
// Good: Always return the error interface
func Good() error { /*...*/ }Error strings should not be capitalized and should not end with punctuation. Exception: exported names, proper nouns, or acronyms.
// Bad
err := fmt.Errorf("Something bad happened.")
// Good
err := fmt.Errorf("something bad happened")When a function returns an error, callers must treat all non-error return values as unspecified unless explicitly documented.
Tip: Functions taking a context.Context should usually return an error so callers can determine if the context was cancelled.
When encountering an error, make a deliberate choice — do not discard with _:
log.Fatal or panicTo intentionally ignore: add a comment explaining why.
n, _ := b.Write(p) // never returns a non-nil errorFor related concurrent operations, use errgroup:
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error { return task1(ctx) })
g.Go(func() error { return task2(ctx) })
if err := g.Wait(); err != nil { return err }Don't return -1, nil, or empty string to signal errors. Use multiple returns:
// Bad: In-band error value
func Lookup(key string) int // returns -1 for missing
// Good: Explicit error or ok value
func Lookup(key string) (string, bool)Handle errors before normal code. Early returns keep the happy path unindented:
// Good: Error first, normal code unindented
if err != nil {
return err
}
// normal codeHandle errors once — either log or return, never both:
Error encountered?
├─ Caller can act on it? → Return (with context via %w)
├─ Top of call chain? → Log and handle
└─ Neither? → Log at appropriate level, continueRead references/ERROR-FLOW.md when structuring complex error flows, deciding between logging vs returning, implementing the handle-once pattern, or choosing structured logging levels.
Advisory: Recommended best practice.
| Caller needs to match? | Message type | Use |
|---|---|---|
| No | static | errors.New("message") |
| No | dynamic | fmt.Errorf("msg: %v", val) |
| Yes | static | var ErrFoo = errors.New("...") |
| Yes | dynamic | custom error type |
Default: Wrap with fmt.Errorf("...: %w", err). Escalate to sentinels for errors.Is(), to custom types for errors.As().
Read references/ERROR-TYPES.md when defining sentinel errors, creating custom error types, or choosing error strategies for a package API.
Advisory: Recommended best practice.
errors.Is/errors.AsKey rules: Place %w at the end. Add context callers don't have. If annotation adds nothing, return err directly.
Read references/WRAPPING.md when deciding between %v and %w, wrapping errors across package boundaries, or adding contextual information.
Validation: After implementing error handling, runbash scripts/check-errors.shto detect common anti-patterns. Then rungo vet ./...to catch additional issues.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.