victorzhuk/skills

z-go-errors

Idiomatic Go error handling, wrapping, inspection, and hygiene — the single handling rule, sentinel vs typed errors, panic discipline.

Vedi sorgente

Come usare

  1. Copia il comando e controlla il pacchetto prima di installarlo nel tuo ambiente agente.
  2. Controlla strumenti, credenziali e ambienti richiesti nel documento originale.
  3. Descrivi input e risultato desiderato; confronta l’output con le fonti.
npx skills add https://github.com/victorzhuk/skills --skill z-go-errors

Prima di iniziare

  • L’installazione non include abbonamenti, quote API o accesso ai file.
  • Stelle e installazioni indicano attività, non un test indipendente di qualità o sicurezza.
Documento Skill originale

Contenuto dal repository con titoli, esempi, codice, tabelle, link e immagini preservati.

Go errors

Core rules

  1. Check every error — never discard with _.
  2. Wrap with context: fmt.Errorf("create user: %w", err) — short prefix, lowercase, no period.
  3. Translate errors at transport boundaries — %v removes wrapping but does not sanitize the message. Return stable public errors; retain internal causes for one safe log.
  4. Inspect via `errors.Is` / `errors.As` — never == on wrapped errors or bare type assertions.
  5. Handle exactly once — log OR return, never both (see Single Handling below).
  6. Panic only for truly unrecoverable states — programmer errors, broken invariants; never for expected conditions.

Wrapping and inspection

go
// wrap
return fmt.Errorf("fetch user %s: %w", id, err)

// sentinel check — works through the chain
if errors.Is(err, ErrNotFound) { ... }

// typed check
var ve *ValidationError
if errors.As(err, &ve) { ... }

// combine independent errors (Go 1.20+)
return errors.Join(errA, errB)

Sentinel vs custom type

Use sentinelUse custom type
Expected condition, no data neededNeed to carry fields (code, field, user message)
Leaf error, never needs unwrappingCallers need to extract structured data
Simple errors.Is check is enoughNeed errors.As to extract structured data
go
// sentinel — unexported, exported error value
var ErrNotFound = errors.New("not found")

// custom type — carries data
type ValidationError struct {
    Field   string
    Message string
}
func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation %s: %s", e.Field, e.Message)
}

Error var names: ErrFoo. Error type names: FooError. Error strings: lowercase, no trailing punctuation.

Single handling rule

An error must be logged OR returned, never both. Violating this creates duplicate log lines and buries the wrapped chain during incidents.

Interior code (repos, services, domain): wrap and return only.

go
// before — log-and-return violation
if err != nil {
    logger.Error("query failed", "err", err)
    return fmt.Errorf("query: %w", err)
}

// after
if err != nil {
    return fmt.Errorf("query: %w", err)
}

Boundary code (HTTP handler, gRPC interceptor, worker loop, main): log and absorb. Never log inside interior layers; the boundary does it once.

go
// boundary: worker loop
for job := range w.jobs {
    if err := w.process(ctx, job); err != nil {
        w.logger.Error("job failed", "job_id", job.ID, "err", err)
        // handle: retry, mark failed, etc.
    }
}

False positives — do NOT fix

PatternWhy it's OK
Log + return nil / continueError absorbed; logging IS the single handling
Log in goroutine that can't returnNo caller to propagate to
Boundary handler logs + returns HTTP statusIt IS the top-level handler
Log + panic / os.Exit / log.FatalTerminal, not propagation
Deferred cleanup (defer tx.Rollback())Can't return errors to caller
Metrics counter + return errorMetrics are aggregations, not per-event log noise

Panic discipline

go
// Only for programmer errors / broken invariants
func mustPositive(n int) int {
    if n <= 0 {
        panic(fmt.Sprintf("mustPositive: got %d", n))
    }
    return n
}

Do not recover an unexpected panic merely to keep a server or worker alive. A broken invariant can leave shared state unsafe even when the goroutine exits.

If an existing package uses an internal panic protocol, recover only its private panic type at the package boundary and re-panic every unexpected value. Define the returned error and resource cleanup. Any broader containment boundary must establish state isolation, define the failed operation's result, and preserve stack diagnostics; a goroutine boundary alone provides no such guarantee.

Quick reference

PatternRule
Wrap format"create user: %w" — short, lowercase, no period
Chain exposurewrap internally; translate to a safe public error at transport boundaries
Sentinel matcherrors.Is(err, ErrFoo)
Typed extractionerrors.As(err, &target)
Join independenterrors.Join(errA, errB)
Single handlinglog OR return; boundary logs, interior wraps
Panic scopeProgrammer errors and broken invariants only
RecoveryOwned panic protocol or explicit containment; re-panic unexpected values
Error var nameErrFoo
Error type nameFooError

Do not

  • Log AND return in the same error branch (interior code).
  • Use == to compare errors that may be wrapped.
  • Use bare type assertions on errors — use errors.As.
  • Produce high-cardinality data in the stable log message; attach as structured attrs.
  • Expose raw internal errors to external callers — translate at the boundary.
  • Convert every panic to an error or log entry without a containment contract.

Verify

sh
go build ./... && timeout 5m go test -parallel 4 -p 2 -short -timeout 2m ./...
golangci-lint run ./...

Review any recovery path for its accepted panic values, unexpected-value propagation, cleanup, and explicit failure result.

Sources

dallo stesso repository

Altri Skills

Tutti gli Skills
victorzhuk
Community

z-accessibility

Audit and improve web accessibility following WCAG 2.2 guidelines. Use when asked to "improve accessibility", "a11y audit", "WCAG compliance", "screen reader support", "keyboard navigation", or "make accessible".

installazioni
1
GitHub Stars
0
Aggiornato
22 ott
victorzhuk
Community

z-algo-core

DS/algorithm selection judgment for production code, not competitive tricks — hash map for membership/dedup, slice+sort beats a tree until proven, heap for top-k, two-pointer/sliding-window for scans, BFS/DFS/topo-sort for dependency shapes. Triggers on Big-O, hash map vs tree. Does not cover profiling/tuning; see [[z-go-performance]].

installazioni
1
GitHub Stars
0
Aggiornato
22 ott
victorzhuk
Community

z-bdd

BDD acceptance contracts for humans and agents across UI, API, and CLI products. Use for Gherkin, Given-When-Then, E2E acceptance, or scenario evidence. Define repeatable scenarios with explicit assertions and required outcomes. Test selection belongs to [[z-testing-strategy]]. Go harness wiring belongs to [[z-go-bdd]].

installazioni
1
GitHub Stars
0
Aggiornato
22 ott
victorzhuk
Community

z-codegraph

Use an existing CodeGraph integration for call graphs, impact analysis, affected tests, or route discovery. Discover installed tools and index freshness; follow host LSP precedence and verify current source. Do not initialize indexes without user authorization.

installazioni
1
GitHub Stars
0
Aggiornato
22 ott