errx

package module
v0.2.7 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2025 License: MIT Imports: 8 Imported by: 18

README

errx: Advanced Error Handling for Go

errx is a flexible error handling package designed to provide structured, extensible, and developer-friendly error management in Go projects. It extends Go's built-in error interface with additional methods, supports gRPC integration, and includes utilities for detailed error tracing and contextual debugging.

Features

  • Extended Error Interface: Add structured details, validation fields, and trace information to errors.
  • gRPC Compatibility: Convert errors to/from gRPC status codes seamlessly.
  • Error Tracing: Automatically track the origin and flow of errors through the system.
  • Customizable Options: Use functional options to customize errors on creation or wrapping.
  • Rich Metadata: Attach contextual information and validation fields for debugging and logging.
  • Integration Utilities: Utilities for extracting or converting errors with functions like AsErrorX, GetCode, and GetType.

Installation

go get github.com/code19m/errx

Usage

0. Helper function for use in examples
func logError(err error) {
	if err == nil {
		return
	}
	e := errx.AsErrorX(err)

	logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{}))
	logger.Error("Error occurred",
		slog.String("err_code", e.Code()),
		slog.String("err_type", e.Type().String()),
		slog.String("err_message", e.Error()),
		slog.String("err_trace", e.Trace()),
		slog.Any("err_fields", e.Fields()),
		slog.Any("err_details", e.Details()),
	)
}
1. Creating Custom Errors
package main

import (
	"log/slog"
	"os"

	"github.com/code19m/errx"
)

func main() {
	err := errx.New("Resource not found",
		errx.WithCode("NOT_FOUND"),                     // Set error code
		errx.WithType(errx.T_NotFound),                 // Set error type
		errx.WithDetails(errx.M{"resource_id": "123"}), // Add additional details
		errx.WithFields(errx.M{"username": "invalid"}), // Add validation fields
	)

	logError(err)
}

Output

{
  "time": "2024-12-08T14:36:34.715364+05:00",
  "level": "ERROR",
  "msg": "Error occurred",
  "err_code": "NOT_FOUND",
  "err_type": "T_NotFound",
  "err_message": "[T_NotFound: NOT_FOUND] - Resource not found",
  "err_trace": "[main.go:28] main.main",
  "err_fields": {
    "username": "invalid"
  },
  "err_details": {
    "resource_id": "123"
  }
}

2. Wrapping Existing Errors
package main

import (
	"errors"
	"log/slog"
	"os"

	"github.com/code19m/errx"
)

func main() {
	baseErr := errors.New("database connection failed")
	err := errx.Wrap(
		baseErr,
		errx.WithDetails(errx.M{
			"host": "localhost",
			"port": "5432",
		}),
	)

	logError(err)
}

Output

{
  "time": "2024-12-08T14:42:44.488966+05:00",
  "level": "ERROR",
  "msg": "Error occurred",
  "err_code": "INTERNAL",
  "err_type": "T_Internal",
  "err_message": "[T_Internal: INTERNAL] - database connection failed",
  "err_trace": "[main.go:30] main.main",
  "err_fields": null,
  "err_details": {
    "host": "localhost",
    "port": "5432"
  }
}

3. Error trace information
package main

import (
	"log/slog"
	"os"

	"github.com/code19m/errx"
)

func main() {
	err := errx.Wrap(firstFunc())

	logError(err)
}

func firstFunc() error {
	return errx.Wrap(secondFunc())
}

func secondFunc() error {
	return errx.New("some error occurred")
}

Output

{
  "time": "2024-12-08T14:49:21.362634+05:00",
  "level": "ERROR",
  "msg": "Error occurred",
  "err_code": "INTERNAL",
  "err_type": "T_Internal",
  "err_message": "[T_Internal: INTERNAL] - some error occurred",
  "err_trace": "[main.go:28] main.main ➡️ [main.go:34] main.firstFunc ➡️ [main.go:38] main.secondFunc",
  "err_fields": null,
  "err_details": null
}

Error Types

The package defines several error types for categorizing errors:

Type Description
T_Internal Internal server errors
T_Validation Input validation errors
T_NotFound Resource not found errors
T_Conflict Conflicting resource errors
T_Authentication Authentication-related errors
T_Forbidden Permission-related errors

Functional Options

Option Description
WithCode Sets a machine-readable error code
WithType Sets the error type
WithPrefix Adds a prefix to trace and details
WithDetails Adds debugging details
WithFields Sets validation-related fields

Testing

Unit tests cover the package functionality. To run tests:

go test ./...

Contributing

Contributions are welcome! Feel free to open issues or submit pull requests.

License

This package is licensed under the MIT License. See the LICENSE file for details.

Documentation

Index

Constants

View Source
const (
	// DefaultCode is the default error code used when no code is provided.
	DefaultCode = ""

	// DefaultType is the default error type used when no type is provided.
	DefaultType = T_Internal
)

Variables

This section is empty.

Functions

func FromGRPCError

func FromGRPCError(err error, opts ...OptionFunc) (bool, error)

FromGRPCError converts a gRPC error into a custom error (ErrorX).

It is intended for use on the gRPC client side after making gRPC calls, to convert gRPC status errors into ErrorX instances. The function returns a boolean indicating whether the error was successfully converted from a proto message (`true`) or not (`false`).

If the error is nil, no action is taken, and the function returns `false, nil`. If the provided error does not contain an ErrorX detail, a default ErrorX instance is created. Optional modifications can be applied via OptionFunc.

***NOTE***: Don't confuse this function with ToGRPCError, which is intended for use on the gRPC server side.

func GetCode

func GetCode(err error) string

GetCode returns the error code if the error implements the ErrorX interface. Otherwise, it returns the default code.

func IsCodeIn added in v0.2.5

func IsCodeIn(err error, codes ...string) bool

IsCodeIn checks if the error's code is in the given list of codes.

func New

func New(msg string, opts ...OptionFunc) error

New creates a new ErrorX with the given message and options.

func ToGRPCError

func ToGRPCError(err error, opts ...OptionFunc) error

ToGRPCError converts a custom error (ErrorX) into a gRPC-compatible error.

It is intended for use in gRPC server handlers/interceptors to convert ErrorX instances to gRPC status errors. If the error is nil, no action is taken, so it is safe to call this function with a nil error.

If the provided error does not implement the ErrorX interface, it is wrapped into a default ErrorX instance.

Optional modifications can be applied via OptionFunc.

***NOTE***: Don't confuse this function with FromGRPCError, which is intended for use in gRPC client side.

func Wrap

func Wrap(err error, opts ...OptionFunc) error

Wrap wraps an error in an errorX instance with the given options.

This function serves as a convenience wrapper around New, enriching the error with additional information and a trace.

It is designed to be used in the middle layers of an application.

func WrapWithTypeOnCodes added in v0.2.5

func WrapWithTypeOnCodes(err error, type_ Type, codes ...string) error

WrapWithTypeOnCodes wraps the error with the given type if the error's code matches any of the provided codes. If the error's code doesn't match any of the codes, the error type is set to T_Internal.

This function is useful for changing the error type based on its code. For example, you can convert an internal error to a validation error if its code matches a known validation error code.

If the error is nil, nil is returned.

Types

type D added in v0.2.5

type D map[string]any

D is a shorthand for a map of string to any value pairs for detailed debugging information.

type ErrorX

type ErrorX interface {

	// Error returns a human-readable description of the error.
	// It implements the standard error interface.
	Error() string

	// Code returns a machine-readable error code.
	// This is intended for use in application logic.
	Code() string

	// Type returns the type of the error.
	// Useful for categorizing errors during error handling.
	Type() Type

	// Trace returns the error's trace information.
	// This can help identify the error's origin in the system.
	Trace() string

	// Fields provides information about input validation errors.
	// Example: {"field_name": "error_message/validation_rule"}
	// Not to be confused with Details, which is used for debugging.
	Fields() M

	// Details provides additional debugging information about the error.
	// This is intended for logging and troubleshooting purposes.
	Details() D

	// Is methos implements the standard errors.Is function.
	// It reports whether any error in the error's tree matches the target.
	Is(target error) bool

	// IsRetriable returns whether the error is retriable.
	// Retriable errors can be retried with backoff strategies.
	IsRetriable() bool
}

ErrorX represents a main interface of this package. It extends the built-in error interface with additional methods to provide structured error information and facilitate debugging.

func AsErrorX

func AsErrorX(err error) ErrorX

AsErrorX returns the error as an ErrorX instance.

If the error does not implement the ErrorX interface, it converts it to an ErrorX with default values.

This function is useful when you want to work with ErrorX instances.

***NOTE***: Make sure that error is not nil before calling this function.

type M

type M map[string]string

M is a shorthand for a map of string key-value pairs.

type OptionFunc

type OptionFunc func(*errorX)

OptionFunc is a function that modifies an errorX.

func WithCode

func WithCode(code string) OptionFunc

WithCode sets the error code. If this option is not used, the default code is "INTERNAL".

func WithDetails

func WithDetails(details D) OptionFunc

WithDetails adds additional contextual information (metadata) to the error. If a key already exists, the new value is appended to the existing value, with the new value appearing first, separated by a "|" character if both values are strings.

func WithFields

func WithFields(fields M) OptionFunc

WithFields sets specific validation related fields. Unlike WithDetails, this method does not append but completely overwrites the existing fields.

Example of fields: {"username": "too short", "email": "invalid format"}

func WithRetriable added in v0.2.6

func WithRetriable() OptionFunc

WithRetriable marks an error as retriable. Retriable errors can be safely retried with appropriate backoff strategies. This can be useful for transient errors like network issues or temporary service unavailability.

func WithTracePrefix added in v0.2.5

func WithTracePrefix(prefix string) OptionFunc

WithTracePrefix adds a prefix to the trace, specifically designed for error propagation between microservices, particularly in gRPC communication.

The trace is changed in the format ">>> prefix >>> %s".

func WithType

func WithType(t Type) OptionFunc

WithType sets the error type. If this option is not used, the default type is T_Internal.

type Type

type Type uint8

Type defines the different categories of errors that can be represented by an ErrorX.

const (
	// Internal errors indicate unexpected issues within the application.
	T_Internal Type = iota

	// Validation errors occur when user input does not meet expected criteria.
	T_Validation

	// NotFound errors are returned when a requested resource cannot be located.
	T_NotFound

	// Conflict errors occur when a resource already exists.
	T_Conflict

	// Authentication errors occur when a user is not authorized to access a resource.
	T_Authentication

	// Forbidden errors occur when a user is not allowed to access a resource.
	T_Forbidden

	// Throttling errors occur when a user has sent too many requests in a given time frame.
	T_Throttling
)

func GetType

func GetType(err error) Type

GetType returns the error type if the error implements the ErrorX interface. Otherwise, it returns the default type.

func (Type) String

func (t Type) String() string

String returns a string representation of the error type.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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