Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
cxuu avatar

Go Error Handling

  • 929 installs
  • 137 repo stars
  • Updated June 20, 2026
  • cxuu/golang-skills

go-error-handling is a Go coding skill that enforces clean, readable error handling patterns for developers who want to avoid nested branches and duplicated logging in Go services.

About

go-error-handling is a cxuu/golang-skills guide to error flow in Go, centered on the handle-once principle and logging decisions that keep the normal code path visible. It teaches indent-error-flow by handling errors before proceeding, avoiding else-clause normal paths, and cautioning against if-with-initializer patterns for long-lived variables. Developers reach for go-error-handling when refactoring noisy if err != nil blocks or standardizing logging across a Go codebase. The skill is pattern-oriented with concrete good-and-bad Go snippets rather than a standalone linter binary.

  • Indent error flow so normal path stays unindented and easy to follow
  • Avoid if-with-initializer for variables used across many lines
  • Handle each error only once: return, log-and-degrade, or match-and-handle
  • Never both log and return the same error
  • 3 core error-flow decision rules

Go Error Handling by the numbers

  • 929 all-time installs (skills.sh)
  • +39 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #426 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
  • Security screen: LOW risk (skills.sh audit)
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/cxuu/golang-skills --skill go-error-handling

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs929
repo stars137
Security audit3 / 3 scanners passed
Last updatedJune 20, 2026
Repositorycxuu/golang-skills

How do you structure idiomatic Go error handling?

Enforce clean, readable Go error handling patterns that prevent nested code and duplicated logging.

Who is it for?

Go backend developers refactoring error-heavy functions who want readable control flow aligned with handle-once logging discipline.

Skip if: Teams needing automated lint enforcement across naming or packages instead of manual error-flow pattern guidance.

When should I use this skill?

The user writes or reviews Go error handling, mentions handle-once logging, nested if err blocks, or wants cleaner error flow in Go packages.

What you get

Go code with early error returns, single-point logging, and an unindented normal execution path.

  • Refactored Go error-handling patterns
  • Readable unindented normal code paths

Files

SKILL.mdMarkdownGitHub ↗

Go Error Handling

Compatibility: errors.Is, errors.As, and %w wrapping require Go 1.13+; structured logging examples may use log/slog from Go 1.21+.

Resource Routing

  • scripts/check-errors.sh - Run when checking string-based error matching, bare error propagation, and log-and-return patterns.
  • scripts/check-errors-ast.go - Implementation helper invoked by check-errors.sh; patch this when changing error-flow analysis behavior.
  • references/ERROR-FLOW.md - Read when deciding where to handle, wrap, log, or return errors.
  • references/ERROR-TYPES.md - Read when choosing sentinel errors, typed errors, or opaque errors.
  • references/WRAPPING.md - Read when choosing %w versus %v or crossing package boundaries.

In Go, errors are values — they are created by code and consumed by code.

Choosing an Error Strategy

1. System boundary (RPC, IPC, storage)? → Wrap with %v to avoid leaking internals 2. Caller needs to match specific conditions? → Sentinel or typed error, wrap with %w 3. Caller just needs debugging context? → fmt.Errorf("...: %w", err) 4. Leaf function, no wrapping needed? → Return the error directly

Default: wrap with %w and place it at the end of the format string.

---

Core Rules

Never Return Concrete Error Types

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

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")

For displayed messages (logs, test failures, API responses), capitalization is appropriate.

Return Values on Error

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.

---

Handling Errors

When encountering an error, make a deliberate choice — do not discard with _:

1. Handle immediately — address the error and continue 2. Return to caller — optionally wrapped with context 3. In exceptional caseslog.Fatal or panic

To intentionally ignore: add a comment explaining why.

n, _ := b.Write(p) // never returns a non-nil error

For 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 }

Avoid In-Band Errors

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)

This prevents callers from writing Parse(Lookup(key)) — it causes a compile-time error since Lookup(key) has 2 outputs.

---

Error Flow

Handle errors before normal code. Early returns keep the happy path unindented:

// Good: Error first, normal code unindented
if err != nil {
    return err
}
// normal code

Handle 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, continue

---

Error Types

Advisory: Recommended best practice.
Caller needs to match?Message typeUse
Nostaticerrors.New("message")
Nodynamicfmt.Errorf("msg: %v", val)
Yesstaticvar ErrFoo = errors.New("...")
Yesdynamiccustom error type

Default: Wrap with fmt.Errorf("...: %w", err). Escalate to sentinels for errors.Is(), to custom types for errors.As().

---

Error Wrapping

Advisory: Recommended best practice.
  • Use `%v`: At system boundaries, for logging, to hide internal details
  • Use `%w`: To preserve error chain for errors.Is/errors.As

Key rules: Place %w at the end. Add context callers don't have. If annotation adds nothing, return err directly.

Validation: After implementing error handling, run bash scripts/check-errors.sh to detect common anti-patterns. Then run go vet ./... to catch additional issues.

---

Related Skills

  • Error naming: See go-naming when naming sentinel errors (ErrFoo) or custom error types
  • Testing errors: See go-testing when testing error semantics with errors.Is/errors.As or writing error-checking helpers
  • Panic handling: See go-defensive when deciding between panic and error returns, or writing recover guards
  • Guard clauses: See go-control-flow when structuring early-return error flow or reducing nesting
  • Logging decisions: See go-logging when choosing log levels, configuring structured logging, or deciding what context to include in log messages

Related skills

FAQ

What is the handle-once principle in go-error-handling?

go-error-handling applies handle-once so each error is logged or handled at a single point, preventing duplicated log statements while keeping the normal Go execution path unindented and easy to read.

How should normal code appear after errors in Go?

go-error-handling recommends handling errors first and returning or continuing before normal code runs, avoiding else branches that hide the primary execution path behind extra indentation.

Is Go Error Handling safe to install?

skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.