Agent Native

go-error-handling

This skill guides agents writing Go error handling by choosing between sentinel errors, custom types, and wrapping strategies using fmt.Errorf with %w or %v.

by cxuuCommunityNot reviewed

Community author

Agents
Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode
License
Apache-2.0 (permissive)
Pin
91f0c2epinned Oct 9, 2026
Context cost
about 1,400 tokenswhen the skill loads
GitHub stars
171on cxuu/golang-skills
Scripts
2 scripts

What it does

“Use when writing Go code that returns, wraps, or handles errors — choosing between sentinel errors, custom types, and fmt.Errorf (%w vs %v), structuring error flow, or deciding whether to log or return. Also use when propagating errors across package boundaries or using errors.Is/As, even if the user doesn't ask about error strategy. Does not cover panic/recover patterns (see go-defensive).”
The author's description, from SKILL.md

Generated summary from the skill's own text

This skill guides agents writing Go error handling by choosing between sentinel errors, custom types, and wrapping strategies using fmt.Errorf with %w or %v. It covers when to return, wrap, log, or handle errors, how to structure error flow for readability, and validation via included shell scripts and reference documentation.

When to use it

  • Writing Go functions that return errors or handle failures
  • Deciding whether to wrap errors with %w or %v across packages
  • Structuring error handling to avoid log-and-return anti-patterns
  • Implementing errors.Is or errors.As matching for specific error types

When not to

  • Handling panic and recovery patterns, use go-defensive instead
  • Testing error semantics in unit tests, use go-testing instead
  • Choosing log levels or structuring log messages, use go-logging instead

Install

These commands install from the publisher's repository and need no account.

skills CLI

npx skills add cxuu/golang-skills --skill go-error-handling

Installs from the repository's default branch, which may have changed since the commit we checked.

GitHub CLI 2.90 or later

gh skill install cxuu/golang-skills go-error-handling@91f0c2eef559a3168f9d3c38f5f99936d472b508

Installs the commit we checked (91f0c2e).

Copy by hand

Download the folder at 91f0c2e and put it in .claude/skills/go-error-handling for Claude Code and in .agents/skills/go-error-handling for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode.

Skill folder on GitHub at 91f0c2e

Copy for your agent

A prompt for any coding agent. It installs this skill from GitHub at the pinned commit, copies the files as they are, and runs nothing unless you ask.

Prompt

Install the agent skill "go-error-handling" by cxuu.

Source, pinned to commit 91f0c2eef559a3168f9d3c38f5f99936d472b508:
https://github.com/cxuu/golang-skills/tree/91f0c2eef559a3168f9d3c38f5f99936d472b508/skills/go-error-handling

1. Download that folder at exactly this commit. Do not use the default branch.
2. Copy every file unchanged, keeping the folder structure, into .claude/skills/go-error-handling/ for Claude Code and .agents/skills/go-error-handling/ for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode. Create the folders if they do not exist.
3. Do not edit the files, and do not run any script in the folder unless I ask you to.
4. When you are done, list the files you copied and where you put them.

Listing and checks: https://www.agentnative.dev/skills/cxuu/go-error-handling

SKILL.md at the pin

---
name: go-error-handling
description: Use when writing Go code that returns, wraps, or handles errors — choosing between sentinel errors, custom types, and fmt.Errorf (%w vs %v), structuring error flow, or deciding whether to log or return. Also use when propagating errors across package boundaries or using errors.Is/As, even if the user doesn't ask about error strategy. Does not cover panic/recover patterns (see go-defensive).
allowed-tools: Bash(bash:*)
---

# 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](https://go.dev/blog/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:

```go
// 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.

```go
// 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 cases** — `log.Fatal` or `panic`

To intentionally ignore: add a comment explaining why.

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

For related concurrent operations, use
[`errgroup`](https://pkg.go.dev/golang.org/x/sync/errgroup):

```go
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:

```go
// 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:

```go
// 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 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()`.

---

## 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](../go-naming/SKILL.md) when naming sentinel errors (`ErrFoo`) or custom error types
- **Testing errors**: See [go-testing](../go-testing/SKILL.md) when testing error semantics with `errors.Is`/`errors.As` or writing error-checking helpers
- **Panic handling**: See [go-defensive](../go-defensive/SKILL.md) when deciding between panic and error returns, or writing recover guards
- **Guard clauses**: See [go-control-flow](../go-control-flow/SKILL.md) when structuring early-return error flow or reducing nesting
- **Logging decisions**: See [go-logging](../go-logging/SKILL.md) when choosing log levels, configuring structured logging, or deciding what context to include in log messages

From cxuu/golang-skills at 91f0c2e, shown as plain text under its license: Apache-2.0 (permissive). The license text is in LICENSE.

View SKILL.md on GitHub at 91f0c2e

Files

6 files, 30 KB in total. Each file has a sha256 in the pin's manifest; the first 12 characters are shown.

Skill folder on GitHub at 91f0c2e
All Coding workflow skills
  • golang-cli

    This skill guides building Go CLI applications using Cobra for commands and flags, Viper for configuration layering, and Unix best practices.

    by samberCommunity

    Contains scripts

    Claude Code · about 2.3K tokens · pinned 6 days ago

  • planning

    This skill orchestrates multi-workflow projects with dependencies and shared data tables by creating a task graph in the orchestrator via the create-tasks tool.

    by n8nOfficial publisher

    Claude Code, Codex, Cursor +3 · about 2.4K tokens · pinned 6 days ago

  • progressive-building

    This skill implements incremental workflow development for agents building or extending workflows.

    by n8nOfficial publisher

    Claude Code, Codex, Cursor +3 · about 1.4K tokens · pinned 6 days ago

  • workflow-builder

    Builds and edits n8n workflows using the TypeScript SDK.

    by n8nOfficial publisher

    Claude Code, Codex, Cursor +3 · about 14.2K tokens · pinned 6 days ago

  • remotion-upgrade

    This skill upgrades Remotion and its related packages to the latest stable version.

    by RemotionOfficial publisher

    Claude Code, Codex, Cursor +3 · about 460 tokens · pinned 6 days ago

  • remotion-upgrade

    This skill upgrades Remotion and related packages across a project, automatically detecting the package manager and workspaces.

    by RemotionOfficial publisher

    Claude Code, Codex, Cursor +3 · about 460 tokens · pinned 6 days ago

The skills listed here are third-party software, collected from public GitHub repositories as a catalog of recent skills and provided as is. Agent Native does not write or control them and is not responsible for any harm, loss or damage caused by installing or using them. Labels and checks describe what we saw at one commit and are not a guarantee. Read a skill's files before you run it. Terms of use