К основному содержанию
скилл CX Codex

go-error-handling · eduardo-sl — скилл для Claude Code: обработка ошибок в Go

Скилл задаёт агенту правила работы с ошибками в Go: обёртка через %w, sentinel-ошибки, свои типы и errors.Is/errors.As.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add eduardo-sl/go-agent-skills --skill go-error-handling -a claude-code
Открыть на GitHub

Что делает go-error-handling

Скилл описывает, как в Go создавать, оборачивать и проверять ошибки. Внутри — дерево решений: простая ошибка через errors.New, добавление контекста через fmt.Errorf с %w, sentinel-ошибки уровня пакета для случаев, когда вызывающий код должен распознать сбой, и свои типы, если ошибка несёт структурированные данные.

Отдельные разделы — про Unwrap у типа-обёртки, про правило обрабатывать ошибку ровно один раз (логировать или возвращать, но не то и другое), про именование (Err для sentinel, суффикс Error для типов, сообщения строчными без точки) и про границы модуля: что публиковать через %w, а что прятать за %v. Есть и правила паники — только для сломанной инициализации и нарушенных инвариантов.

Скилл рассчитан на работу в проекте на Go, поэтому нужен тулчейн Go: без него команды go и gofmt из списка разрешённых инструментов ничего не сделают. Часть материала вынесена в references/patterns-and-boundaries.md и подгружается по необходимости. Если в проекте есть своё правило про обработку ошибок, оно перекрывает этот скилл.

Какие задачи решает

  • обернуть ошибку из базы так, чтобы вызывающий код мог её распознать
  • завести sentinel-ошибку для «не найдено» и проверять её через errors.Is
  • сделать свой тип ошибки с полями и не порвать цепочку Unwrap
  • убрать двойную обработку, когда ошибка и логируется, и возвращается
  • решить, отдавать ли внутреннюю ошибку наружу или спрятать за %v

Примеры запросов агенту

  • Оберни ошибки в getUser через %w и добавь контекст с id
  • Заведи sentinel-ошибки для «не найдено» и «нет доступа» и проверяй их через errors.Is
  • Сделай тип ValidationError с полем Field и доставай его через errors.As

Как установить go-error-handling

1Через Skills CLI (Vercel)

npx skills add eduardo-sl/go-agent-skills --skill go-error-handling -a claude-code

2Вручную: положить файлы

~/.claude/skills/go-error-handling/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/go-error-handling/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о go-error-handling

Как установить go-error-handling в Claude Code?

Выполните npx skills add eduardo-sl/go-agent-skills --skill go-error-handling -a claude-code. Скилл окажется в ~/.claude/skills/go-error-handling/SKILL.md.

Что делает go-error-handling?

Даёт агенту набор правил по обработке ошибок в Go: дерево решений для создания ошибок, обёртка с %w, sentinel-ошибки, свои типы с Unwrap, именование и поведение на границах модуля.

Чем этот скилл отличается от go-api-design и go-test-quality?

Он про обработку ошибок в обычном коде. Паника и recover в middleware — это go-api-design, а проверки в тестах — go-test-quality.

Исходный текст

SKILL.md · MIT
---
name: go-error-handling
description: >
  Go error handling patterns, wrapping, sentinel errors, custom error types,
  and the errors package. Grounded in Effective Go, Go Code Review Comments,
  and production-proven idioms. Use when implementing error handling,
  designing error types, debugging error chains, or reviewing error handling
  patterns. Trigger examples: "handle errors", "error wrapping", "custom
  error type", "sentinel errors", "errors.Is", "errors.As".
  Not for: panic/recover in middleware (go-api-design), test assertions
  (go-test-quality).
user-invocable: true
license: MIT
compatibility: Designed for Claude Code or similar AI coding agents working on Go projects. Requires the Go toolchain.
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(gofmt:*)
metadata:
  author: eduardo-sl
  version: "1.3.1"
---

# Go Error Handling

Go's explicit error handling is a feature, not a limitation.
These patterns ensure errors are informative, actionable, and properly propagated.

> Community default. A project skill or agent-config rule that explicitly
> supersedes `go-error-handling` takes precedence over this one.

Detailed reference material, loaded on demand:

- `references/patterns-and-boundaries.md` — checking patterns, `Is`
  methods, translating errors at the HTTP boundary, low-cardinality logging,
  the Go 1.27 vet check on `%w` with pointer errors.

Read a reference file only when the summary below is not enough.

## 1. Error Decision Tree

When creating or returning an error, follow this tree:

1. **Simple, no extra context needed?** → `errors.New("message")`
2. **Need to add context to existing error?** → `fmt.Errorf("doing X: %w", err)`
3. **Caller needs to detect this error?** → Sentinel `var` or custom type
4. **Error carries structured data?** → Custom type implementing `error`
5. **Propagating from downstream?** → Wrap with `%w` and add context

## 2. Sentinel Errors

Use package-level `var` for errors that callers need to check:

```go
// ✅ Good — exported sentinel error
var (
    ErrNotFound     = errors.New("user: not found")
    ErrUnauthorized = errors.New("user: unauthorized")
)

// Naming convention: Err + Description
// Prefix with package context in the message
```

Callers check with `errors.Is`:

```go
if errors.Is(err, user.ErrNotFound) {
    // handle not found
}
```

NEVER compare errors with `==`. Always use `errors.Is()`.

## 3. Custom Error Types

When errors need to carry structured information:

```go
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation: field %s: %s", e.Field, e.Message)
}

// Callers extract it from the chain — Go 1.26+:
if valErr, ok := errors.AsType[*ValidationError](err); ok {
    log.Printf("invalid field: %s", valErr.Field)
}

// Before Go 1.26:
var valErr *ValidationError
if errors.As(err, &valErr) {
    log.Printf("invalid field: %s", valErr.Field)
}
```

A custom type that wraps a cause must expose it, or `errors.Is`/`errors.As`
stop at your type and never see the error underneath:

```go
type QueryError struct {
    Query string
    Err   error
}

func (e *QueryError) Error() string { return "query " + e.Query + ": " + e.Err.Error() }
func (e *QueryError) Unwrap() error { return e.Err } // keeps the chain walkable
```

## 4. Error Wrapping

ALWAYS add context when propagating errors up the stack.
Use `%w` to preserve the error chain:

```go
// ✅ Good — context added, chain preserved
func getUser(id int64) (*User, error) {
    row, err := db.QueryRow(ctx, query, id)
    if err != nil {
        return nil, fmt.Errorf("get user %d: %w", id, err)
    }
    // ...
}

// ❌ Bad — no context
return nil, err

// ❌ Bad — chain broken, callers can't errors.Is/As
return nil, fmt.Errorf("failed: %v", err)
```

### When NOT to use `%w`

Use `%v` instead of `%w` when you explicitly want to **break** the error chain,
preventing callers from depending on internal implementation errors:

```go
// Intentionally hiding internal DB error from public API
return nil, fmt.Errorf("user lookup failed: %v", err)
```

## 5. Handle Errors Exactly Once

An error should be either logged OR returned, never both:

```go
// ✅ Good — return the error, let caller decide
func loadConfig(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("load config %s: %w", path, err)
    }
    // ...
}

// ❌ Bad — log AND return (error handled twice)
func loadConfig(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        log.Printf("failed to read config: %v", err) // handled once
        return nil, err                                 // handled again
    }
    // ...
}
```

The rule: the component that *decides what to do* about the error is the one
that logs/metrics it. Everyone else wraps and returns.

## 6. Error Naming Conventions

```go
// Sentinel errors: Err prefix
var ErrNotFound = errors.New("not found")

// Error types: Error suffix
type NotFoundError struct { ... }
type ValidationError struct { ... }

// Error messages: lowercase, no punctuation, no "failed to" prefix
// Include context: "package: action: detail"
errors.New("auth: token expired")
fmt.Errorf("user: get by id %d: %w", id, err)
```

## 7. Panic Rules

Panic is NOT error handling. Use panic only when:
- Program initialization fails and cannot continue (`template.Must`, flag parsing)
- Programmer error that should never happen (violated invariant)
- Nil dereference that indicates a bug, not a runtime condition

In tests, use `t.Fatal` / `t.FailNow`, never `panic`.

In HTTP handlers and middleware, recover from panics at the boundary
to prevent one request from crashing the server.

## 8. Error Checking Patterns

- Scope the error to the `if` when nothing else needs it:
  `if err := do(); err != nil { return fmt.Errorf("do: %w", err) }`.
- A deferred wrap on a named `err` result adds one prefix to every return
  path of a long function.
- Collect independent failures (validation, parallel work) and return
  `errors.Join(errs...)` — `errors.Is`/`As` see every joined error.

## 9. Errors at Boundaries

- **Publishing an error is a contract.** Inside the module, wrap with `%w`.
  At a boundary you publish (an exported library API, an RPC), `%w` makes
  the wrapped error part of your API; `%v` or a new error keeps it private.
- **Translate before it reaches a user.** Map domain errors to a status
  and a stable message at the handler, and log the original once with its
  chain. `err.Error()` in a response leaks SQL, paths and hostnames.
- **Keep logged messages low-cardinality.** The stable text is the message;
  IDs, paths and counts go in structured attributes so the log backend can
  group identical failures.
- **Panics do not cross goroutines.** A `recover` only works in the
  goroutine that panicked — see go-concurrency-review.
- **Implement `Is(target error) bool`** on a type to let `errors.Is` match a
  whole family of errors against one sentinel.

Examples for sections 8 and 9: `references/patterns-and-boundaries.md`.

## Executable Verification

After writing or reviewing error handling, run the linters that prove
the rules above (skip any that is not installed and note it):

```bash
go vet ./...                                  # includes printf %w misuse
golangci-lint run --enable errcheck,errorlint # unchecked errors, %v-vs-%w,
                                              # == comparisons on errors
```

## Verification Checklist

1. No `_` discarding errors (unless explicitly justified with comment)
2. Every `fmt.Errorf` wrapping uses `%w` (or `%v` with documented reason)
3. Sentinel errors use `var Err...` naming
4. Custom error types implement `error` interface
5. Callers use `errors.Is` / `errors.As` (`errors.AsType` on Go 1.26+), never `==` or type assertion
6. Custom types that wrap a cause implement `Unwrap() error`
7. No log-and-return patterns
8. Error messages are lowercase, contextual, chain-friendly
9. No `err.Error()` text in responses to users; logged messages are stable, details are attributes

© eduardo-sl · MIT · eduardo-sl/go-agent-skills

Похожие скиллы

Все скиллы по теме «Языки программирования» →

Сначала — go-error-handling от других авторов.

go-error-handling cxuu Скилл учит агента писать надёжную обработку ошибок в Go: выбирать между %w и %v, задавать sentinel-ошибки и не смешивать логирование с возвратом. CX Codex +1 1 300установок golang-error-handling samber Скилл для идиоматичной обработки ошибок в Go: оборачивание с контекстом, проверка цепочек, структурированное логирование и интеграция с samber/oops. Применяется при создании, оборачивании, инспекции и логировании ошибок. CX Codex +1 43 400установок error-handling affaan-m Скилл задаёт единые правила обработки ошибок в TypeScript, Python и Go: типизированные исключения, ретраи, circuit breaker, тексты для пользователя. CX Codex +1 4 800установок error-handling-patterns Seth Hobson Скилл помогает проектировать обработку ошибок: исключения, Result-типы, передачу контекста и graceful degradation. Пригодится для API и отладки сбоев. CX Codex 22 957установок m06-error-handling actionbook Помогает ИИ-агенту выбирать правильный способ обработки ошибок в Rust. Пригодится, когда нужно решить между Result, Option, panic!, thiserror и anyhow. CX Codex +1 3 500установок python-error-handling Seth Hobson Скилл обучает ассистента правилам обработки ошибок в Python: ранней валидации входных данных и сохранению цепочек исключений. CX Codex 14 116установок Error Handling taste f Промпт задаёт ИИ-ассистенту вкус бэкенд-инженера на TypeScript: как валидировать вход, разделять ожидаемые ошибки и баги, логировать и отдавать клиенту. GP ChatGPT ★ 174 676звёзд репо

Из того же набора11

go-ci Скилл помогает агенту писать и настраивать GitHub Actions для Go-проектов. Нужен, когда нужна пайплайн с линтингом, тестами, проверками безопасности и кешированием. CX Codex +1 ★ 83звёзд репо git-commit Скилл учит агента писать коммиты по Conventional Commits: тип, область, императив в заголовке. Пригодится, когда история коммитов в проекте превратилась в кашу. CX Codex +1 ★ 83звёзд репо go-troubleshooting Скилл ведёт агента по диагностике рантайм-проблем в Go: паники, дедлоки, утечки горутин и памяти, отчёты race detector. Пригодится, когда программа падает или висит, а причина неясна. CX Codex +1 ★ 83звёзд репо go-observability Скилл для Go-сервисов: помогает настроить структурные логи на log/slog, трейсы и метрики через OpenTelemetry, а также алерты по SLO. Пригодится, когда сервис уже в проде и нужно видеть, что в нём происходит. CX Codex +1 ★ 83звёзд репо go-context Скилл для ИИ-агента, который проверяет и правит работу с context.Context в Go: отмена, таймауты, значения, типичные ошибки. CX Codex +1 ★ 83звёзд репо go-project-layout Подсказывает, как разложить новый Go-проект по папкам: cmd/, internal/, плоская раскладка для мелких утилит. Пригодится в самом начале, когда структура ещё не сложилась. CX Codex +1 ★ 83звёзд репо go-grpc Скилл для ИИ-агента, который ведёт разработку gRPC-сервисов на Go: proto-контракты, коды ошибок, дедлайны, интерцепторы и стриминг. CX Codex +1 ★ 83звёзд репо go-dependency-injection Скилл учит агента внедрять зависимости в Go через конструкторы и собирать всё в main. Пригодится, когда в проекте завёлся глобальный синглтон или код тяжело тестировать. CX Codex +1 ★ 83звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой