handle-errors

Implements Go error handling with sentinel errors, wrapping, and connect.Code translation.

Updated Sep 14, 2026
One-click install
npx skills add https://github.com/nakamori-naoya/go-convention-plugins --skill handle-errors-nakamori-naoya
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: handle-errors
Source: https://github.com/nakamori-naoya/go-convention-plugins/tree/main/plugins/go-convention/skills/handle-errors
Command: npx skills add https://github.com/nakamori-naoya/go-convention-plugins --skill handle-errors-nakamori-naoya

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill includes references (resource) components.

What problem does it solve? Go projects often end up with inconsistent error handling: ad-hoc error types, lost error chains, and scattered HTTP/RPC status mapping. This Skill enforces one uniform shape for errors across all layers of a Go DDD application, so every rejection reason in the domain document maps 1:1 to a sentinel error and every translation to connect.Code lives in exactly one table. ## Core Features & Use Cases - Sentinel Derivation: Converts each "rejection reason" in a domain-model document into an errors.New sentinel with Japanese wording and a trailing comment pointing to the source document. - Wrapping and Inspection Rules: Standardizes fmt.Errorf("<operation> <business ID>: %w") once per package boundary, errors.Is for checks, and errors.AsType only at persistence/interceptor boundaries. - Two-Stage Translation: Maps PostgreSQL constraint violations (*pgconn.PgError, pgx.ErrNoRows) to sentinels in the repository layer, then maps sentinels to connect.Code in a single codeTable in the outermost interceptor. - Use Case: Given a reservation domain document listing rejection reasons like "hold deadline passed" or "not the owner", generate errors.go sentinels, wrap errors at each layer boundary, and register each sentinel in the connect.Code table. ## Quick Start Define the errors for this aggregate from the rejection reasons in the attached domain-model document and translate them to connect.Code at the boundary.

Frequently Asked Questions about handle-errors

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I define sentinel errors in Go from a domain model?▼

Create one errors.New value per rejection reason in the domain document, named Err{what was rejected}, in an errors.go file in the aggregate package. Write the message in Japanese without periods, and add a trailing comment citing the document's wording.

How to wrap errors in Go without breaking errors.Is?▼

Use fmt.Errorf with a single %w verb once per package boundary, in the form "<operation> <business ID>: %w". Never use %v, err.Error(), or errors.New(err.Error()), since those sever the chain and prevent errors.Is from reaching the sentinel.

How do I map Go errors to connect.Code in Connect RPC?▼

Keep a single codeTable in handler/error_table.go that maps sentinels to codes via errors.Is, applied by the outermost Logging interceptor. Handler bodies return errors as-is and never call connect.NewError; unmapped errors become Internal with a fixed message.

How should pgx PostgreSQL errors be translated to domain errors?▼

In the repository layer, use errors.AsType[*pgconn.PgError] and match on named constraints, mapping exclusion violations to domain sentinels and unique violations to ErrConflict. Map pgx.ErrNoRows to ErrNotFound only for the aggregate's current row, not dependent rows.

When should a Go function return (T, bool) instead of an error?▼

Return (T, bool) when the document states the operation has no rejection reason and simply changes nothing, such as expiring a hold whose deadline has not arrived. Reserve (T, error) for operations that can actually be rejected or fail.

What are the limitations of sentinel-only error handling in Go?▼

Sentinels carry only the rejection identity, not values like a suspension end time. When a caller needs such values, create one operation-specific typed error whose Is method answers the sentinel, and never build generic Reason/Kind error types.