errors

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 16, 2026 License: MIT Imports: 3 Imported by: 0

README

errors

Semantic and traceable error management for the go-kit ecosystem. Defines failure identity through stable, transport-agnostic error codes, structured context, and cause chaining.

Part of the nochebuenadev/go-kit micro-lib collection.

Features

  • Stable, transport-agnostic error codes — no coupling to HTTP, gRPC, or any protocol
  • Structured context (key-value metadata) attached to each error for tracing and logging
  • Immutable builder API — WithContext and WithError return new instances, safe for package-level reuse
  • Full errors.Is / errors.As traversal via Unwrap
  • JSON serialization out of the box for API responses
  • Zero external dependencies
  • Exported Error interface for loose coupling between consumers

Installation

go get code.nochebuena.dev/go/errors

Requires Go 1.21 or later.

Quick start

import "code.nochebuena.dev/go/errors"

// Create a typed error.
err := errors.New(errors.ErrInvalidInput, "username is required")
fmt.Println(err.Error())
// INVALID_ARGUMENT: username is required

// Wrap an existing error and attach context.
err = errors.Wrap(errors.ErrInternal, "failed to save user", originalErr).
    WithContext("user_id", 42).
    WithContext("operation", "create")

fmt.Println(err.Detailed())
// code: INTERNAL_ERROR | message: failed to save user | Cause: ... | context: map[operation:create user_id:42]

// Coerce any error into the canonical type.
typed := errors.From(someErr)
fmt.Println(typed.GetCode()) // INTERNAL_ERROR (if someErr is not already an *errors.Err)

Constructors

Primary constructors
Function Description
New(code ErrorCode, message string) *Err Creates a new error with the given code and message.
Wrap(code ErrorCode, message string, err error) *Err Creates a new error wrapping an existing cause.
From(err error) *Err Coerces any error into *Err. Returns nil for nil input, unwraps existing *Err via errors.As, and wraps unknown errors as ErrInternal.
Shorthand helpers
Function Code
InvalidInput(msg string, args ...any) *Err ErrInvalidInput
NotFound(msg string, args ...any) *Err ErrResourceNotFound
Internal(msg string, args ...any) *Err ErrInternal

All shorthand helpers accept a fmt.Sprintf-style format string.

Builder methods

Both methods return a new *Err — the original is never modified.

Method Description
WithContext(key string, value any) *Err Adds a key-value pair to the error's structured context.
WithError(err error) *Err Sets the underlying cause of the error.
Error codes
Constant Value Semantic meaning
ErrInvalidInput INVALID_ARGUMENT Input is malformed or fails validation.
ErrUnauthorized UNAUTHENTICATED Caller identity could not be verified.
ErrPermissionDenied PERMISSION_DENIED Caller is authenticated but lacks permissions.
ErrResourceNotFound NOT_FOUND Requested resource does not exist or is not accessible.
ErrConflict ALREADY_EXISTS State conflict such as a duplicate or violated uniqueness constraint.
ErrPreconditionFailed FAILED_PRECONDITION System is not in the state required to execute the operation.
ErrRateLimited RESOURCE_EXHAUSTED Caller exceeded an allowed quota or rate limit.
ErrInternal INTERNAL_ERROR Unexpected failure within the system.
ErrNotImplemented NOT_IMPLEMENTED Requested operation has not been implemented.
ErrUnavailable SERVICE_UNAVAILABLE A required dependency is temporarily unreachable.
ErrDeadlineExceeded TIMEOUT Operation did not complete within the allowed time.

Mapping these codes to protocol-specific representations (HTTP status codes, gRPC codes, etc.) is the responsibility of the transport layer.

Environment variables

This package does not read any environment variables.

Interfaces

Error

The canonical interface consumers should depend on. Accepting Error rather than *Err prevents coupling to the concrete implementation.

type Error interface {
    error                         // Error() string
    GetCode() string              // machine-readable error code
    GetContext() map[string]any   // structured metadata, always non-nil
    Detailed() string             // verbose representation for logging
}

Usage in consumers:

// In a logging or middleware layer — no import of *Err needed.
func logError(err errors.Error) {
    log.Printf("code=%s context=%v msg=%s", err.GetCode(), err.GetContext(), err.Error())
}

The logz micro-lib integrates with this package through duck typing: it checks at runtime whether an error exposes GetCode() and GetContext() without importing this module directly.

Architecture

error.go        — Error interface, Err struct, constructors, builder methods, JSON marshaling
error_code.go   — ErrorCode type and the 11 predefined constants with their descriptions
doc.go          — Package-level documentation

Immutability. WithContext and WithError perform a shallow clone of the struct and a full copy of the context map before returning a new instance. This makes it safe to define package-level sentinel errors and enrich them per call site without data races.

// Safe: each call site gets its own *Err with its own context map.
var ErrUserNotFound = errors.NotFound("user not found")

func handler(userID int) error {
    return ErrUserNotFound.WithContext("user_id", userID)
}

Cause chaining. Err implements Unwrap() error, enabling standard errors.Is and errors.As traversal through the full cause chain.

JSON serialization. *Err implements json.Marshaler. The output omits context when empty.

{"code":"NOT_FOUND","message":"user not found","context":{"user_id":42}}

License

MIT License. Copyright (c) 2026 NOCHEBUENADEV. See LICENSE for details.

Documentation

Overview

Package errors provides semantic and traceable error management for the go-kit ecosystem.

It defines failure identity through stable error codes, human-readable messages, structured context, and cause chaining. Errors produced by this package carry enough information to be logged, serialized, and programmatically handled without coupling to any transport layer.

Example usage:

// Create a typed error directly.
err := errors.New(errors.ErrInvalidInput, "username is required")
fmt.Println(err.Error())
// Output: INVALID_ARGUMENT: username is required

// Wrap an existing error with context.
wrapped := errors.Wrap(errors.ErrInternal, "failed to save user", originalErr).
	WithContext("user_id", 42)

// Coerce any error into the library's canonical type.
typed := errors.From(someErr)
fmt.Println(typed.GetCode())

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Err

type Err struct {
	// contains filtered or unexported fields
}

Err represents a semantic application error with a stable code, human-readable message, optional underlying cause, and structured context for tracing.

func From

func From(err error) *Err

From converts any error into a *Err. If err is nil, nil is returned. If the error is already a *Err (or wraps one), it is returned as-is. Otherwise, it is wrapped with ErrInternal and the original error preserved as the cause.

func Internal

func Internal(msg string, args ...any) *Err

Internal creates a new Err with ErrInternal code. It accepts a format string and arguments for the message.

func InvalidInput

func InvalidInput(msg string, args ...any) *Err

InvalidInput creates a new Err with ErrInvalidInput code. It accepts a format string and arguments for the message.

func New

func New(code ErrorCode, message string) *Err

New creates a new Err with the given code and message.

func NotFound

func NotFound(msg string, args ...any) *Err

NotFound creates a new Err with ErrResourceNotFound code. It accepts a format string and arguments for the message.

func Wrap

func Wrap(code ErrorCode, message string, err error) *Err

Wrap creates a new Err that wraps an existing error with a code and message.

func (*Err) Detailed

func (e *Err) Detailed() string

Detailed returns a more verbose string representation of the error, including its code, message, cause, and full context.

func (*Err) Error

func (e *Err) Error() string

Error returns a formatted string representation of the error. It includes the code, the message, and the underlying error if present.

func (*Err) GetCode

func (e *Err) GetCode() string

GetCode returns the string representation of the error code.

func (*Err) GetContext

func (e *Err) GetContext() map[string]any

GetContext returns the contextual data associated with the error. If no context exists, it returns an empty map.

func (*Err) MarshalJSON

func (e *Err) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface.

func (*Err) Unwrap

func (e *Err) Unwrap() error

Unwrap returns the underlying cause of the error, satisfying the errors.Unwrap convention and enabling errors.Is / errors.As traversal.

func (*Err) WithContext

func (e *Err) WithContext(key string, value any) *Err

WithContext returns a new *Err with the given key-value pair added to the context. The original error is not modified.

func (*Err) WithError

func (e *Err) WithError(err error) *Err

WithError returns a new *Err with the given error set as the underlying cause. The original error is not modified.

type Error

type Error interface {
	// error satisfies the built-in error interface.
	error

	// GetCode returns the machine-readable error code as a string.
	GetCode() string

	// GetContext returns the structured key-value metadata attached to the error.
	// Always returns a non-nil map.
	GetContext() map[string]any

	// Detailed returns a verbose, structured representation suitable for logging.
	Detailed() string
}

Error is the canonical interface for all errors produced by this package. Consumers such as loggers or middleware should accept this interface rather than the concrete *Err type to avoid coupling.

type ErrorCode

type ErrorCode string

ErrorCode represents a unique identifier for a specific type of error. These codes are stable, transport-agnostic identifiers. Mapping to protocol-specific representations (e.g. HTTP status codes, gRPC codes) is the responsibility of the transport layer.

const (
	// ErrInvalidInput indicates that the provided input is malformed or does not meet
	// validation requirements.
	ErrInvalidInput ErrorCode = "INVALID_ARGUMENT"

	// ErrUnauthorized indicates that the caller's identity could not be verified.
	ErrUnauthorized ErrorCode = "UNAUTHENTICATED"

	// ErrPermissionDenied indicates that the caller's identity is known but lacks the
	// required permissions.
	ErrPermissionDenied ErrorCode = "PERMISSION_DENIED"

	// ErrResourceNotFound indicates that a requested resource does not exist or is not
	// accessible.
	ErrResourceNotFound ErrorCode = "NOT_FOUND"

	// ErrConflict indicates a state conflict, such as a duplicate or a violated
	// uniqueness constraint.
	ErrConflict ErrorCode = "ALREADY_EXISTS"

	// ErrPreconditionFailed indicates that the operation was rejected because the
	// system is not in a state required to execute it (e.g. enabling a resource that
	// must first be configured).
	ErrPreconditionFailed ErrorCode = "FAILED_PRECONDITION"

	// ErrRateLimited indicates that the caller has exceeded an allowed quota or rate
	// and must back off before retrying.
	ErrRateLimited ErrorCode = "RESOURCE_EXHAUSTED"

	// ErrInternal indicates an unexpected failure within the system.
	ErrInternal ErrorCode = "INTERNAL_ERROR"

	// ErrNotImplemented indicates that the requested operation has not been implemented.
	ErrNotImplemented ErrorCode = "NOT_IMPLEMENTED"

	// ErrUnavailable indicates that a required dependency is temporarily unreachable.
	ErrUnavailable ErrorCode = "SERVICE_UNAVAILABLE"

	// ErrDeadlineExceeded indicates that the operation did not complete within the
	// allowed time.
	ErrDeadlineExceeded ErrorCode = "TIMEOUT"
)

func (ErrorCode) Description

func (c ErrorCode) Description() string

Description returns a human-readable description for the error code. If the code is unknown, it returns the code itself as a string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL