Categorygithub.com/pingcap/errcode
modulepackage
0.3.0
Repository: https://github.com/pingcap/errcode.git
Documentation: pkg.go.dev

# README

About Error codes

Error codes are particularly useful to reliably communicate the error type across program (network) boundaries. A program can reliably respond to an error if it can be sure to understand its type. Error monitoring systems can reliably understand what errors are occurring.

errcode overview

This package extends go errors via interfaces to have error codes. The two main goals are

  • The clients can reliably understand errors by checking against error codes.
  • Structure information is sent to the client

See the go docs for extensive API documentation.

There are other packages that add error code capabilities to errors. However, they almost universally use a single underlying error struct. A code or other annotation is a field on that struct. In most cases a structured error response is only possible to create dynamically via tags and labels.

errcode instead follows the model of pkg/errors to use wrapping and interfaces. You are encouraged to make your own error structures and then fulfill the ErrorCode interface by adding a function. Additional features (for example annotating the operation) are done via wrapping.

This design makes errcode highly extensible, inter-operable, and structure preserving (of the original error). It is easy to gradually introduce it into a project that is using pkg/errors (or the Cause interface).

Features

  • structured error representation
  • Follows the pkg/errors model where error enhancements are annotations via the Causer interface.
  • Internal errors show a stack trace but others don't.
  • Operation annotation. This concept is explained here.
  • Works for multiple errors when the Errors() interface is used. See the Combine function for constructing multiple error codes.
  • Extensible metadata. See how SetHTTPCode is implemented.
  • Integration with existing error codes
    • HTTP
    • GRPC (provided by separate grpc package)

Example

// First define a normal error type
type PathBlocked struct {
	start     uint64 `json:"start"`
	end       uint64 `json:"end"`
	obstacle  uint64 `json:"end"`
}

func (e PathBlocked) Error() string {
	return fmt.Sprintf("The path %d -> %d has obstacle %d", e.start, e.end, e.obstacle)
}

// Define a code. These often get re-used between different errors.
// Note that codes use a hierarchy to share metadata.
// This code is a child of the "state" code.
var PathBlockedCode = errcode.StateCode.Child("state.blocked")

// Now attach the code to your custom error type.
func (e PathBlocked) Code() Code {
	return PathBlockedCode
}

var _ ErrorCode = (*PathBlocked)(nil)  // assert implements the ErrorCode interface

Now lets see how you can send the error code to a client in a way that works with your exising code.

// Given just a type of error, give an error code to a client if it is present
if errCode := errcode.CodeChain(err); errCode != nil {
	// If it helps, you can set the code a header
	w.Header().Set("X-Error-Code", errCode.Code().CodeStr().String())

	// But the code will also be in the JSON body
	// Codes have HTTP codes attached as meta data.
	// You can also attach other kinds of meta data to codes.
	// Our error code inherits StatusBadRequest from its parent code "state"
	rd.JSON(w, errCode.Code().HTTPCode(), errcode.NewJSONFormat(errCode))
}

Let see a usage site. This example will include an annotation concept of "operation".

func moveX(start, end, obstacle) error {}
	op := errcode.Op("path.move.x")

	if start < obstable && obstacle < end  {
		return op.AddTo(PathBlocked{start, end, obstacle})
	}
}

Development

./scripts build
./scripts test
./scripts check

# Packages

Package grpc attaches GRPC codes to the standard error codes.

# Functions

ClientData retrieves data from a structure that implements HasClientData If HasClientData is not defined it will use the given ErrorCode object.
CodeChain resolves an error chain down to a chain of just error codes Any ErrorGroups found are converted to a MultiErrCode.
Combine constructs a MultiErrCode.
ErrorCodes return all errors (from an ErrorGroup) that are of interface ErrorCode.
NewCode creates a new top-level code.
NewCodedError is for constructing broad error kinds (e.g.
NewForbiddenErr creates a forbiddenErr from an err.
NewInternalErr creates an internalError from an err.
NewInvalidInputErr creates an invalidInput from an err.
NewJSONFormat turns an ErrorCode into a JSONFormat.
NewNotAuthenticatedErr creates a notAuthenticatedErr from an err.
NewNotFoundErr creates a notFound from an err.
NewStackCode constructs a StackCode, which is an ErrorCode with stack trace information The second variable is an optional stack position gets rid of information about function calls to construct the stack trace.
NewUnimplementedErr creates an internalError from an err.
Op adds an operation to an ErrorCode with AddTo.
Operation will return an operation string if it exists.
OperationClientData gives the results of both the ClientData and Operation functions.
StackTrace retrieves the errors.StackTrace from the error if it is present.

# Variables

AlreadyExistsCode indicates an attempt to create an entity failed because it already exists.
AuthCode represents an authentication or authorization issue.
ForbiddenCode indicates the user is not authorized.
InternalCode is equivalent to HTTP 500 Internal Server Error.
InvalidInputCode is equivalent to HTTP 400 Bad Request.
NotAuthenticatedCode indicates the user is not authenticated.
NotFoundCode is equivalent to HTTP 404 Not Found.
OutOfRangeCode indicates an operation was attempted past a valid range.
StateCode is an error that is invalid due to the current system state.
UnimplementedCode is mapped to HTTP 501.

# Structs

ChainContext is returned by ErrorCodeChain to retain the full wrapped error message of the error chain.
A Code has a CodeStr representation.
CodedError is a convenience to attach a code to an error and already satisfy the ErrorCode interface.
EmbedOp is designed to be embedded into your existing error structs.
JSONFormat is an opinion on how to serialize an ErrorCode to JSON.
A MultiErrCode contains at least one ErrorCode and uses that to satisfy the ErrorCode and related interfaces The Error method will produce a string of all the errors with a semi-colon separation.
OpErrCode is an ErrorCode with an Operation field attached.
StackCode is an ErrorCode with stack trace information attached.

# Interfaces

Causer allows the abstract retrieval of the underlying error.
ErrorCode is the interface that ties an error and RegisteredCode together.
HasClientData is used to defined how to retrieve the data portion of an ErrorCode to be returned to the client.
HasOperation is an interface to retrieve the operation that occurred during an error.

# Type aliases

AddOp is constructed by Op.
CodeStr is the name of the error code.
MetaData is used in a pattern for attaching meta data to codes and inheriting it from a parent.