errors

package module
v0.3.6 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2023 License: MIT Imports: 10 Imported by: 32

README

go-errors

GoVersion GoDoc License Report

master Test codecov

dev Test codecov

This is a library for handling errors in Go language.

Usage

This package combines Go standard errors package and github.com/pkg/errors.

All funcs from both packages are available.

On top of them, I added some sentinels for common errors I need all the time.

All sentinels are from the same type which contains various information. Whenever a sentinel is used, a StackTrace is also generated.

Here is how to use the errors:

func findme(stuff map[string]string, key string) (string, error) {
    if value, found := stuff[key]; found {
        return value, nil
    }
    return "", errors.NotFound.With("key", key)
}

func main() {
    var allstuff[string]string
    //...
    value, err := findme("key1")
    if errors.Is(err, errors.NotFound) {
        fmt.Fprintf(os.Stderr, "Error: %+v", err)
        // This should print the error its wrapped content and a StackTrace.
    }
}

If you plan to do something with the content of the error, you would try that:

func main() {
    var allstuff[string]string
    //...
    value, err := findme("key1")
    if errors.Is(err, errors.NotFound) {
        var details *errors.Error
        if errors.As(err, &details) {
            fmt.Fprintf(os.Stderr, "Could not find %s", details.What)
        }
    }
}

Note: You should not use var details errors.Error, use the pointer version var details *errors.Error instead.

When several errors.Error are chained up, this can be used to extract the ones you want:

func main() {
    var allstuff[string]string
    //...
    value, err := findme("key1")
    if errors.Is(err, errors.NotFound) {
        details := errors.NotFound.Clone()
        if errors.As(err, &details) {
            fmt.Fprintf(os.Stderr, "Could not find %s", details.What)
        }
    }
}

To return an HTTP Status as an error, you could do this:

func doit() error {
    req, err := http.NewRequest(http.MethodGet, "http://www.acme.org")
    if err != nil {
        return errors.WithStack(err)
    }
    httpclient := http.DefaultClient()
    res, err := httpclient.Do(req)
    if err != nil {
        return errors.WithStack(err)
    }
    if res.StatusCode >= 400 {
        return errors.FromHTTPStatusCode(res.StatusCode)
    }
    return nil
}

func main() {
    err := doit()
    if (errors.Is(err, errors.HTTPBadRequest)) {
        // do something
    }
    // do something else
}

You can chain multiple errors together (See Example):

func doit() error {
    // ... some processing
    var urlError *url.Error // errors from the net/url package

    return errors.WrapErrors(err, errors.NotFound.With("key", "key1"), urlError)
}

You can also use a errors.MultiError to collect multiple errors together (See Example):

me := errors.MultiError{}
me.Append(errors.NotFound.With("key", "key1"))
me.Append(errors.NotFound.With("key", "key2"))
fmt.Println(me.AsError())

Finally, errors.Error supports JSON serialization:

err := errors.InvalidType.With("bogus")
payload, jerr := json.Marshal(err)
// ...

Documentation

Overview

This package combines Go standard errors package (https://pkg.go.dev/errors) and github.com/pkg/errors(https://github.com/pkg/errors).

All funcs from both packages are available.

On top of them, I added some sentinels for common errors I need all the time.

All sentinels are from the same type which contains various information. Whenever a sentinel is used, a StackTrace is also generated.

Here is how to use the errors:

func findme(stuff map[string]string, key string) (string, error) {
    if value, found := stuff[key]; found {
        return value, nil
    }
    return "", errors.NotFound.With(key).WithStack()
}

func main() {
    var allstuff[string]string
    //...
    value, err := findme("key1")
    if errors.Is(err, errors.NotFound) {
        fmt.Fprintf(os.Stderr, "Error: %+v", err)
        // This should print the error its wrapped content and a StackTrace.
    }
}

If you plan to do something with the content of the error, you would try that:

func main() {
    var allstuff[string]string
    //...
    value, err := findme("key1")
    if errors.Is(err, errors.NotFound) {
        var details *errors.Error
        if errors.As(err, &details) {
            fmt.Fprintf(os.Stderr, "Could not find %s", details.What)
        }
    }
}

Note: You should not use "var details errors.Error", use the pointer version "var details *errors.Error" instead.

When several `errors.Error` are chained up, this can be used to extract the ones you want:

func main() {
		var allstuff[string]string
		//...
		value, err := findme("key1")
		if errors.Is(err, errors.NotFound) {
				details := errors.NotFound.Clone()
				if errors.As(err, &details) {
						fmt.Fprintf(os.Stderr, "Could not find %s", details.What)
				}
		}
}

To return an HTTP Status as an error, you could do this:

func doit() error {
	req, err := http.NewRequest(http.MethodGet, "http://www.acme.org")
	if err != nil {
		return errors.WithStack(err)
	}
	httpclient := http.DefaultClient()
	res, err := httpclient.Do(req)
	if err != nil {
		return errors.WithStack(err)
	}
	if res.StatusCode >= 400 {
		return errors.FromHTTPStatusCode(res.StatusCode)
	}
	return nil
}

func main() {
	err := doit()
	if (errors.Is(err, errors.HTTPBadRequest)) {
		// do something
	}
	// do something else
}

You can also add more than one _cause_ to an `errors.Error`, turning it into a _multi-error_ container:

err := errors.Error{}
err.WithCause(errors.ArgumentInvalid.With("key", "value"))
err.WithCause(errors.ArgumentMissing.With("key"))
err.WithCause(fmt.Errorf("some simple string error"))

Finally, errors.Error supports JSON serialization.

err := errors.InvalidType.With("bogus")
payload, jerr := json.Marshal(err)
// ...

Index

Examples

Constants

This section is empty.

Variables

View Source
var ArgumentExpected = NewSentinel(http.StatusBadRequest, "error.argument.expected", "Argument %s is invalid (value: %v, expected: %v)")

ArgumentExpected is used when an argument is expected and another was set.

View Source
var ArgumentInvalid = NewSentinel(http.StatusBadRequest, "error.argument.invalid", "Argument %s is invalid (value: %v)")

ArgumentInvalid is used when an argument has an unexpected value.

View Source
var ArgumentMissing = NewSentinel(http.StatusBadRequest, "error.argument.missing", "Argument %s is missing")

ArgumentMissing is used when an argument is missing.

View Source
var CreationFailed = NewSentinel(http.StatusInternalServerError, "error.creation.failed", "Failed Creating %s")

CreationFailed is used when something was not created properly.

View Source
var DuplicateFound = NewSentinel(http.StatusFound, "error.found", "%s %s Found")

DuplicateFound is used when something is found but it should not have been.

View Source
var Empty = NewSentinel(http.StatusBadRequest, "error.empty", "%s is empty")

Empty is used when something is empty whereas it should not.

View Source
var EnvironmentInvalid = NewSentinel(http.StatusBadRequest, "error.environment.invalid", "Environment variable %s is invalid (value: %v)")

EnvironmentInvalid is used when an argument has an unexpected value.

View Source
var EnvironmentMissing = NewSentinel(http.StatusBadRequest, "error.environment.missing", "Environment variable %s is missing")

EnvironmentMissing is used when an argument is missing.

View Source
var HTTPBadGateway = NewSentinel(http.StatusBadGateway, "error.http.gateway", http.StatusText(http.StatusBadGateway))

HTTPBadGateway is used when an http.Client request fails.

View Source
var HTTPBadRequest = NewSentinel(http.StatusBadRequest, "error.http.request", http.StatusText(http.StatusBadRequest)+". %s")

HTTPBadRequest is used when an http.Client request fails.

View Source
var HTTPForbidden = NewSentinel(http.StatusForbidden, "error.http.forbidden", http.StatusText(http.StatusForbidden))

HTTPForbidden is used when an http.Client request fails.

View Source
var HTTPInternalServerError = NewSentinel(http.StatusInternalServerError, "error.http.server", http.StatusText(http.StatusInternalServerError))

HTTPInternalServerError is used when an http.Client request fails.

View Source
var HTTPMethodNotAllowed = NewSentinel(http.StatusMethodNotAllowed, "error.http.notallowed", http.StatusText(http.StatusMethodNotAllowed))

HTTPMethodNotAllowed is used when an http.Client request fails.

View Source
var HTTPNotFound = NewSentinel(http.StatusNotFound, "error.http.notfound", http.StatusText(http.StatusNotFound))

HTTPNotFound is used when an http.Client request fails.

View Source
var HTTPNotImplemented = NewSentinel(http.StatusNotImplemented, "error.http.notimplemented", http.StatusText(http.StatusNotImplemented))

HTTPNotImplemented is used when an http.Client request fails.

View Source
var HTTPServiceUnavailable = NewSentinel(http.StatusServiceUnavailable, "error.http.unavailable", http.StatusText(http.StatusServiceUnavailable))

HTTPServiceUnavailable is used when an http.Client request fails.

View Source
var HTTPStatusConflict = NewSentinel(http.StatusConflict, "error.http.conflict", http.StatusText(http.StatusConflict))

HTTPStatusConflict reports HTTP Error StatusConflict.

View Source
var HTTPStatusExpectationFailed = NewSentinel(http.StatusExpectationFailed, "error.http.expectation.failed", http.StatusText(http.StatusExpectationFailed))

HTTPStatusExpectationFailed reports HTTP Error StatusExpectationFailed.

View Source
var HTTPStatusFailedDependency = NewSentinel(http.StatusFailedDependency, "error.http.failed.dependency", http.StatusText(http.StatusFailedDependency))

HTTPStatusFailedDependency reports HTTP Error StatusFailedDependency.

View Source
var HTTPStatusGatewayTimeout = NewSentinel(http.StatusGatewayTimeout, "error.http.gateway.timeout", http.StatusText(http.StatusGatewayTimeout))

HTTPStatusGatewayTimeout reports HTTP Error StatusGatewayTimeout.

View Source
var HTTPStatusGone = NewSentinel(http.StatusGone, "error.http.gone", http.StatusText(http.StatusGone))

HTTPStatusGone reports HTTP Error StatusGone.

View Source
var HTTPStatusHTTPVersionNotSupported = NewSentinel(http.StatusHTTPVersionNotSupported, "error.http.unsupported.version", http.StatusText(http.StatusHTTPVersionNotSupported))

HTTPStatusHTTPVersionNotSupported reports HTTP Error StatusHTTPVersionNotSupported.

View Source
var HTTPStatusInsufficientStorage = NewSentinel(http.StatusInsufficientStorage, "error.http.storage.insufficient", http.StatusText(http.StatusInsufficientStorage))

HTTPStatusInsufficientStorage reports HTTP Error StatusInsufficientStorage.

View Source
var HTTPStatusLengthRequired = NewSentinel(http.StatusLengthRequired, "error.http.length.required", http.StatusText(http.StatusLengthRequired))

HTTPStatusLengthRequired reports HTTP Error StatusLengthRequired.

View Source
var HTTPStatusLocked = NewSentinel(http.StatusLocked, "error.http.locked", http.StatusText(http.StatusLocked))

HTTPStatusLocked reports HTTP Error StatusLocked.

View Source
var HTTPStatusLoopDetected = NewSentinel(http.StatusLoopDetected, "error.http.loop.detected", http.StatusText(http.StatusLoopDetected))

HTTPStatusLoopDetected reports HTTP Error StatusLoopDetected.

View Source
var HTTPStatusMisdirectedRequest = NewSentinel(http.StatusMisdirectedRequest, "error.http.misdirect.request", http.StatusText(http.StatusMisdirectedRequest))

HTTPStatusMisdirectedRequest reports HTTP Error StatusMisdirectedRequest.

View Source
var HTTPStatusNetworkAuthenticationRequired = NewSentinel(http.StatusNetworkAuthenticationRequired, "error.http.network.authentication.required", http.StatusText(http.StatusNetworkAuthenticationRequired))

HTTPStatusNetworkAuthenticationRequired reports HTTP Error StatusNetworkAuthenticationRequired.

View Source
var HTTPStatusNotAcceptable = NewSentinel(http.StatusNotAcceptable, "error.http.notacceptable", http.StatusText(http.StatusNotAcceptable))

HTTPStatusNotAcceptable reports HTTP Error StatusNotAcceptable.

View Source
var HTTPStatusNotExtended = NewSentinel(http.StatusNotExtended, "error.http.notextended", http.StatusText(http.StatusNotExtended))

HTTPStatusNotExtended reports HTTP Error StatusNotExtended.

View Source
var HTTPStatusPaymentRequired = NewSentinel(http.StatusPaymentRequired, "error.http.payment.required", http.StatusText(http.StatusPaymentRequired))

HTTPStatusPaymentRequired reports HTTP Error StatusPaymentRequired.

View Source
var HTTPStatusPreconditionFailed = NewSentinel(http.StatusPreconditionFailed, "error.http.precondition.failed", http.StatusText(http.StatusPreconditionFailed))

HTTPStatusPreconditionFailed reports HTTP Error StatusPreconditionFailed.

View Source
var HTTPStatusPreconditionRequired = NewSentinel(http.StatusPreconditionRequired, "error.precondition.required", http.StatusText(http.StatusPreconditionRequired))

HTTPStatusPreconditionRequired reports HTTP Error StatusPreconditionRequired.

View Source
var HTTPStatusProxyAuthRequired = NewSentinel(http.StatusProxyAuthRequired, "error.http.proxy.authentication.required", http.StatusText(http.StatusProxyAuthRequired))

HTTPStatusProxyAuthRequired reports HTTP Error StatusProxyAuthRequired.

View Source
var HTTPStatusRequestEntityTooLarge = NewSentinel(http.StatusRequestEntityTooLarge, "error.http.request.entity.toolarge", http.StatusText(http.StatusRequestEntityTooLarge))

HTTPStatusRequestEntityTooLarge reports HTTP Error StatusRequestEntityTooLarge.

View Source
var HTTPStatusRequestHeaderFieldsTooLarge = NewSentinel(http.StatusRequestHeaderFieldsTooLarge, "error.http.request.fields.toolarge", http.StatusText(http.StatusRequestHeaderFieldsTooLarge))

HTTPStatusRequestHeaderFieldsTooLarge reports HTTP Error StatusRequestHeaderFieldsTooLarge.

View Source
var HTTPStatusRequestTimeout = NewSentinel(http.StatusRequestTimeout, "error.http.request.timeout", http.StatusText(http.StatusRequestTimeout))

HTTPStatusRequestTimeout reports HTTP Error StatusRequestTimeout.

View Source
var HTTPStatusRequestURITooLong = NewSentinel(http.StatusRequestURITooLong, "error.http.request.uri.toolong", http.StatusText(http.StatusRequestURITooLong))

HTTPStatusRequestURITooLong reports HTTP Error StatusRequestURITooLong.

View Source
var HTTPStatusRequestedRangeNotSatisfiable = NewSentinel(http.StatusRequestedRangeNotSatisfiable, "error.http.request.range.notstatisfiable", http.StatusText(http.StatusRequestedRangeNotSatisfiable))

HTTPStatusRequestedRangeNotSatisfiable reports HTTP Error StatusRequestedRangeNotSatisfiable.

View Source
var HTTPStatusTeapot = NewSentinel(http.StatusTeapot, "error.http.teapot", http.StatusText(http.StatusTeapot))

HTTPStatusTeapot reports HTTP Error StatusTeapot.

View Source
var HTTPStatusTooEarly = NewSentinel(http.StatusTooEarly, "error.http.tooearly", http.StatusText(http.StatusTooEarly))

HTTPStatusTooEarly reports HTTP Error StatusTooEarly.

View Source
var HTTPStatusTooManyRequests = NewSentinel(http.StatusTooManyRequests, "error.http.request.toomany", http.StatusText(http.StatusTooManyRequests))

HTTPStatusTooManyRequests reports HTTP Error StatusTooManyRequests.

View Source
var HTTPStatusUnavailableForLegalReasons = NewSentinel(http.StatusUnavailableForLegalReasons, "error.http.unavailable", http.StatusText(http.StatusUnavailableForLegalReasons))

HTTPStatusUnavailableForLegalReasons reports HTTP Error StatusUnavailableForLegalReasons.

View Source
var HTTPStatusUnprocessableEntity = NewSentinel(http.StatusUnprocessableEntity, "error.http.entity.unprocessable", http.StatusText(http.StatusUnprocessableEntity))

HTTPStatusUnprocessableEntity reports HTTP Error StatusUnprocessableEntity.

View Source
var HTTPStatusUnsupportedMediaType = NewSentinel(http.StatusUnsupportedMediaType, "error.http.mediatype.unsupported", http.StatusText(http.StatusUnsupportedMediaType))

HTTPStatusUnsupportedMediaType reports HTTP Error StatusUnsupportedMediaType.

View Source
var HTTPStatusUpgradeRequired = NewSentinel(http.StatusUpgradeRequired, "error.http.upgrade.required", http.StatusText(http.StatusUpgradeRequired))

HTTPStatusUpgradeRequired reports HTTP Error StatusUpgradeRequired.

View Source
var HTTPStatusUseProxy = NewSentinel(http.StatusUseProxy, "error.http.proxy.required", http.StatusText(http.StatusUseProxy))

HTTPStatusUseProxy reports HTTP Error StatusUseProxy.

View Source
var HTTPStatusVariantAlsoNegotiates = NewSentinel(http.StatusVariantAlsoNegotiates, "error.http.variant.alsonegotiate", http.StatusText(http.StatusVariantAlsoNegotiates))

HTTPStatusVariantAlsoNegotiates reports HTTP Error StatusVariantAlsoNegotiates.

View Source
var HTTPUnauthorized = NewSentinel(http.StatusUnauthorized, "error.http.unauthorized", http.StatusText(http.StatusUnauthorized))

HTTPUnauthorized is used when an http.Client request fails.

View Source
var IndexOutOfBounds = NewSentinel(http.StatusBadRequest, "error.index.outofbounds", "Index %s is out of bounds (value: %v)")

IndexOutOfBounds is used when an index is out of bounds.

View Source
var Invalid = NewSentinel(http.StatusBadRequest, "error.invalid", "Invalid %s (value: %v, expected: %v)")

Invalid is used when something is not valid.

View Source
var InvalidType = NewSentinel(http.StatusBadRequest, "error.type.invalid", "Invalid Type %s, expected: %s")

InvalidType is used when a type is not valid.

View Source
var InvalidURL = NewSentinel(http.StatusBadRequest, "error.url.invalid", "Invalid URL %s")

InvalidURL is used when a URL is not valid.

View Source
var JSONMarshalError = NewSentinel(http.StatusBadRequest, "error.json.marshal", "JSON failed to marshal data")

JSONMarshalError is used when data failed to be marshaled into JSON.

View Source
var JSONPropertyMissing = NewSentinel(http.StatusBadRequest, "error.json.property.missing", "JSON data is missing property %s")

JSONPropertyMissing is used when JSON data is missing a property.

View Source
var JSONUnmarshalError = NewSentinel(http.StatusBadRequest, "error.json.unmarshal", "JSON failed to unmarshal data")

JSONUnmarshalError is used when JSON data is missing a property.

View Source
var Missing = NewSentinel(http.StatusBadRequest, "error.missing", "%s is missing")

Missing is used when something is missing.

View Source
var NotConnected = NewSentinel(http.StatusGone, "error.client.not_connected", "%s Not Connected")

NotConnected is used when some socket, client is not connected to its server.

View Source
var NotFound = NewSentinel(http.StatusNotFound, "error.notfound", "%s %s Not Found")

NotFound is used when something is not found.

View Source
var NotImplemented = NewSentinel(http.StatusNotImplemented, "error.notimplemented", "Not Implemented")

NotImplemented is used when some code/method/func is not written yet.

View Source
var NotInitialized = NewSentinel(http.StatusBadRequest, "error.notinitialized", "%s is not yet initialized")

NotInitialized is used when something is not yet initialized.

View Source
var RuntimeError = NewSentinel(http.StatusInternalServerError, "error.runtime", "Runtime Error")

RuntimeError is used when the code failed executing something.

View Source
var TooManyErrors = NewSentinel(http.StatusInternalServerError, "error.toomany", "Too Many")

TooManyErrors is used when something is found too many times.

View Source
var Unauthorized = NewSentinel(http.StatusUnauthorized, "error.unauthorized", "Invalid Credentials")

Unauthorized is used when some credentials failed some authentication process.

View Source
var UnknownError = NewSentinel(http.StatusInternalServerError, "error.unknown", "Unknown Error: %s")

UnknownError is used when the code does not know which error it is facing...

View Source
var Unsupported = NewSentinel(http.StatusMethodNotAllowed, "error.unsupported", "Unsupported %s: %s")

Unsupported is used when something is unsupported by the code.

View Source
var VERSION = "0.3.6" + commit

VERSION is the version of this application

Functions

func As

func As(err error, target interface{}) bool

As finds the first error in err's chain that matches target, and if so, sets target to that error value and returns true.

The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.

An error matches target if the error's concrete value is assignable to the value pointed to by target, or if the error has a method As(interface{}) bool such that As(target) returns true. In the latter case, the As method is responsible for setting target.

As will panic if target is not a non-nil pointer to either a type that implements error, or to any interface type. As returns false if err is nil.

func Errorf

func Errorf(format string, args ...interface{}) error

Errorf formats according to a format specifier and returns the string as a value that satisfies error.

Errorf also records the stack trace at the point it was called.

func FromHTTPStatusCode

func FromHTTPStatusCode(code int) error

FromHTTPStatusCode creates a new error of the sentinel that matches the given HTTP status code.

It also records the stack trace at the point it was called.

func Is

func Is(err, target error) bool

Is reports whether any error in err's chain matches target.

The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.

An error is considered to match a target if it is equal to that target or if it implements a method Is(error) bool such that Is(target) returns true.

func Join added in v0.3.5

func Join(errors ...error) error

Join returns an error wrapping given errors

If the first or the last error in the chain is nil, Join returns nil.

If one of the errors in the middle of the chain is nil, that error is ignored.

If there is only one error in the chain, Join returns it.

Example
err := errors.Join(
	errors.ArgumentInvalid.With("key", "value"),
	errors.ArgumentMissing.With("key"),
	&url.Error{
		Op:  "GET",
		URL: "https://example.com",
		Err: fmt.Errorf("connection refused"),
	},
)
fmt.Println(err)
Output:

Argument key is invalid (value: value)
Caused by:
	Argument key is missing
Caused by:
	GET "https://example.com": connection refused

func New

func New(message string) error

New returns a new error with the supplied message.

New also records the stack trace at the point it was called.

func Unwrap

func Unwrap(err error) error

Unwrap returns the result of calling the Unwrap method on err, if err's type contains an Unwrap method returning error.

Otherwise, Unwrap returns nil.

func WithMessage

func WithMessage(err error, message string) error

WithMessage annotates err with a new message.

If err is nil, WithMessage returns nil.

func WithMessagef

func WithMessagef(err error, format string, args ...interface{}) error

WithMessagef annotates err with the format specifier.

If err is nil, WithMessagef returns nil.

func WithStack

func WithStack(err error) error

WithStack annotates err with a stack trace at the point WithStack was called.

If err is nil, WithStack returns nil.

If err is already annotated with a stack trace, WithStack returns err.

func WithoutStack added in v0.2.1

func WithoutStack(err error) error

WithoutStack removes the stack trace from the current error

If err is nil, WithStack returns nil.

func Wrap

func Wrap(err error, message string) error

Wrap returns an error annotating err with a stack trace at the point Wrap is called, and the supplied message.

If err is nil, Wrap returns nil.

func WrapErrors added in v0.3.3

func WrapErrors(errors ...error) error

WrapErrors returns an error wrapping given errors

If the first or the last error in the chain is nil, WrapErrors returns nil.

If one of the errors in the middle of the chain is nil, that error is ignored.

If there is only one error in the chain, WrapErrors returns it.

Example
err := errors.WrapErrors(
	errors.ArgumentInvalid.With("key", "value"),
	errors.ArgumentMissing.With("key"),
	&url.Error{
		Op:  "GET",
		URL: "https://example.com",
		Err: fmt.Errorf("connection refused"),
	},
)
fmt.Println(err)
Output:

Argument key is invalid (value: value)
Caused by:
	Argument key is missing
Caused by:
	GET "https://example.com": connection refused

func Wrapf

func Wrapf(err error, format string, args ...interface{}) error

Wrapf returns an error annotating err with a stack trace at the point Wrapf is called, and the format specifier.

If err is nil, Wrapf returns nil.

Types

type Error

type Error struct {
	// Code is an numerical code, like an HTTP Status Code
	Code int `json:"code,omitempty"`
	// ID is the string identifier, like: "error.argument.invalid"
	ID string `json:"id,omitempty"`
	// Text is the human readable error message
	Text string `json:"text,omitempty"`
	// What contains what element is wrong for errors that need it, like NotFoundError
	What string `json:"what,omitempty"`
	// Value contains the value that was wrong for errors that need it, like ArgumentInvalidError
	// TODO: use structpb
	Value interface{} `json:"value,omitempty"`
	// Origin contains the real error from another package, if any
	Origin error `json:"-"`
	// Cause contains the error that caused this error
	Cause error `json:"-"`
	// stack contains the StackTrace when this Error is instanciated
	Stack StackTrace `json:"-"`
}

Error describes an augmented implementation of Go's error interface

Example
err := errors.NewSentinel(500, "error.test.custom", "Test Error").Clone()
fmt.Println(err)

var details *errors.Error
if errors.As(err, &details) {
	fmt.Println(details.ID)
}
Output:

Test Error
error.test.custom

func NewSentinel

func NewSentinel(code int, id, message string) Error

NewSentinel creates a new sentinel.

A sentinel is an Error that hasn't been decorated with a stack trace

Typically, it can be used to create error that can be matched later

func (Error) As added in v0.3.0

func (e Error) As(target interface{}) bool

As attempts to convert the given error into the given target

As returns true if the conversion was successful and the target is now populated.

Example:

target := errors.ArgumentInvalid.Clone()
if errors.As(err, &target) {
  // do something with target
}

func (Error) Clone added in v0.3.0

func (e Error) Clone() *Error

Clone creates an exact copy of this Error

func (Error) Error

func (e Error) Error() string

Error returns the string version of this error.

implements error interface.

func (Error) Format added in v0.2.0

func (e Error) Format(state fmt.State, verb rune)

Format interprets fmt State and rune to generate an output for fmt.Sprintf, etc

implements fmt.Formatter

Example (Default)
err := errors.NotImplemented.WithStack()
if err != nil {
	fmt.Printf("%v\n", err)
}
Output:

Not Implemented
Example (Gosyntax_01)
output := CaptureStdout(func() {
	err := errors.WrapErrors(errors.ArgumentInvalid.With("key", "value"), errors.ArgumentMissing.With("key"))
	if err != nil {
		fmt.Printf("%#v\n", err)
	}
})
// remove the line numbers from the stack trace as they change when the code is changed
simplifier := regexp.MustCompile(`\.go:[0-9]+`)
// we also do not care about the last file which is machine dependent
noasm := regexp.MustCompile(`, asm_.[^\.]+.s:[0-9]+`)
fmt.Println(noasm.ReplaceAllString(simplifier.ReplaceAllString(output, ".go"), ""))
Output:

errors.Error{Code: 400, ID: "error.argument.invalid", Text: "Argument %s is invalid (value: %v)", What: "key", Value: "value", Cause: errors.Error{Code: 400, ID: "error.argument.missing", Text: "Argument %s is missing", What: "key", Stack: []errors.StackFrame{errors_test.go, errors_test.go, errors_test.go, run_example.go, example.go, testing.go, _testmain.go, proc.go}}, Stack: []errors.StackFrame{errors_test.go, errors_test.go, errors_test.go, run_example.go, example.go, testing.go, _testmain.go, proc.go}}
Example (Gosyntax_02)
output := CaptureStdout(func() {
	err := errors.WrapErrors(errors.ArgumentInvalid.With("key", "value"), fmt.Errorf("unknown error"))
	if err != nil {
		fmt.Printf("%#v\n", err)
	}
})
// remove the line numbers from the stack trace as they change when the code is changed
simplifier := regexp.MustCompile(`\.go:[0-9]+`)
// we also do not care about the last file which is machine dependent
noasm := regexp.MustCompile(`, asm_.[^\.]+.s:[0-9]+`)
fmt.Println(noasm.ReplaceAllString(simplifier.ReplaceAllString(output, ".go"), ""))
Output:

errors.Error{Code: 400, ID: "error.argument.invalid", Text: "Argument %s is invalid (value: %v)", What: "key", Value: "value", Cause: "unknown error", Stack: []errors.StackFrame{errors_test.go, errors_test.go, errors_test.go, run_example.go, example.go, testing.go, _testmain.go, proc.go}}
Example (Quoted)
err := errors.NotImplemented.WithStack()
if err != nil {
	fmt.Printf("%q", err)
}
Output:

"Not Implemented"
Example (WithStack)
output := CaptureStdout(func() {
	err := errors.NotImplemented.WithStack()
	if err != nil {
		fmt.Printf("%+v", err)
	}
})
// remove the path of each file and line numbers as they change for each Go deployments
lines := strings.Split(output, "\n")
simplifier := regexp.MustCompile(`\s*(.*/)?(.*):[0-9]+`)
for i := 0; i < len(lines); i++ {
	line := lines[i]
	lines[i] = simplifier.ReplaceAllString(line, "  ${2}")
}
// we also do not care about last line that is machine dependent
fmt.Println(strings.Join(lines[0:len(lines)-1], "\n"))
Output:

Not Implemented
github.com/gildas/go-errors_test.ExampleError_Format_withStack.func1
  errors_test.go
github.com/gildas/go-errors_test.CaptureStdout
  errors_test.go
github.com/gildas/go-errors_test.ExampleError_Format_withStack
  errors_test.go
testing.runExample
  run_example.go
testing.runExamples
  example.go
testing.(*M).Run
  testing.go
main.main
  _testmain.go
runtime.main
  proc.go
runtime.goexit

func (Error) GetID added in v0.2.0

func (e Error) GetID() string

GetID tells the ID of this Error

func (Error) GoString added in v0.2.0

func (e Error) GoString() string

GoString returns the Go syntax of this Error

implements fmt.GoStringer

func (Error) Is

func (e Error) Is(target error) bool

Is tells if this error matches the target.

implements errors.Is interface (package "errors").

To check if an error is an errors.Error, simply write:

if errors.Is(err, errors.Error{}) {
  // do something with err
}

func (Error) MarshalJSON added in v0.1.1

func (e Error) MarshalJSON() ([]byte, error)

MarshalJSON marshals this into JSON

func (*Error) UnmarshalJSON added in v0.1.1

func (e *Error) UnmarshalJSON(payload []byte) (err error)

UnmarshalJSON decodes JSON

func (Error) Unwrap

func (e Error) Unwrap() error

Unwrap gives the first Cause of this Error, if any.

implements errors.Unwrap interface (package "errors").

func (Error) With added in v0.0.2

func (e Error) With(what string, values ...interface{}) error

With creates a new Error from a given sentinel telling "what" is wrong and eventually their value.

With also records the stack trace at the point it was called.

Example
err := errors.ArgumentMissing.With("key")
if err != nil {
	fmt.Println(err)

	var details *errors.Error
	if errors.As(err, &details) {
		fmt.Println(details.ID)
	}
}
Output:

Argument key is missing
error.argument.missing
Example (Array)
err := errors.ArgumentInvalid.With("key", []string{"value1", "value2"})
if err != nil {
	fmt.Println(err)

	var details *errors.Error
	if errors.As(err, &details) {
		fmt.Println(details.ID)
	}
}
Output:

Argument key is invalid (value: [value1 value2])
error.argument.invalid
Example (Value)
err := errors.ArgumentInvalid.With("key", "value")
if err != nil {
	fmt.Println(err)

	var details *errors.Error
	if errors.As(err, &details) {
		fmt.Println(details.ID)
	}
}
Output:

Argument key is invalid (value: value)
error.argument.invalid

func (Error) WithStack added in v0.0.2

func (e Error) WithStack() error

WithStack creates a new error from a given Error and records its stack.

func (Error) WithoutStack added in v0.2.0

func (e Error) WithoutStack() error

WithoutStack creates a new error from a given Error and records its stack.

func (Error) Wrap

func (e Error) Wrap(err error) error

Wrap wraps the given error in this Error.

If err is nil, Wrap returns nil.

Wrap also records the stack trace at the point it was called.

Example
var payload struct {
	Value string `json:"value"`
}

err := json.Unmarshal([]byte(`{"value": 0`), &payload)
if err != nil {
	finalerr := errors.JSONMarshalError.Wrap(err)
	var details *errors.Error
	if errors.As(finalerr, &details) {
		fmt.Println(details.ID)
	}

	fmt.Println(finalerr)

	cause := details.Unwrap()
	if cause != nil {
		fmt.Println(cause)
	}
}
Output:

error.json.marshal
JSON failed to marshal data
Caused by:
	unexpected end of JSON input
unexpected end of JSON input

type MultiError

type MultiError struct {
	Errors []error `json:"errors"`
}

MultiError is used to collect errors, like during a loop

Example
var errs errors.MultiError

errs.Append(
	errors.New("this is the first error"),
	errors.New("this is the second error"),
)
fmt.Println(errs.Error())
Output:

2 errors:
this is the first error
this is the second error

func (*MultiError) Append

func (me *MultiError) Append(errs ...error)

Append appends new errors

If an error is nil, it is not added

func (MultiError) As added in v0.3.4

func (e MultiError) As(target interface{}) bool

As attempts to convert the given error into the given target

The first error to match the target is returned

func (*MultiError) AsError

func (me *MultiError) AsError() error

AsError returns this if it contains errors, nil otherwise

If this contains only one error, that error is returned.

AsError also records the stack trace at the point it was called.

func (*MultiError) Error

func (me *MultiError) Error() string

Error returns the string version of this error

implements error.Error interface

func (MultiError) Is added in v0.3.4

func (e MultiError) Is(target error) bool

Is tells if this error matches the target.

implements errors.Is interface (package "errors").

To check if an error is an errors.Error, simply write:

if errors.Is(err, errors.Error{}) {
  // do something with err
}

func (*MultiError) IsEmpty added in v0.3.4

func (me *MultiError) IsEmpty() bool

IsEmpty returns true if this MultiError contains no errors

type StackFrame added in v0.2.0

type StackFrame uintptr

func (StackFrame) Filepath added in v0.2.0

func (frame StackFrame) Filepath() string

func (StackFrame) Format added in v0.2.0

func (frame StackFrame) Format(s fmt.State, verb rune)

Format formats the frame according to the fmt.Formatter interface.

%s    source file
%d    source line
%n    function name
%v    equivalent to %s:%d

Format accepts flags that alter the printing of some verbs, as follows:

%+s   function name and path of source file relative to the compile time
      GOPATH separated by \n\t (<funcname>\n\t<path>)
%+v   equivalent to %+s:%d

func (StackFrame) FuncName added in v0.2.0

func (frame StackFrame) FuncName() string

func (StackFrame) Line added in v0.2.0

func (frame StackFrame) Line() int

func (StackFrame) MarshalJSON added in v0.2.0

func (frame StackFrame) MarshalJSON() ([]byte, error)

MarshalJSON marshals this into JSON

func (StackFrame) MarshalText added in v0.2.0

func (frame StackFrame) MarshalText() ([]byte, error)

type StackTrace added in v0.2.0

type StackTrace []StackFrame

func (StackTrace) Format added in v0.2.0

func (st StackTrace) Format(s fmt.State, verb rune)

Format formats the stack of Frames according to the fmt.Formatter interface.

%s	lists source files for each Frame in the stack
%v	lists the source file and line number for each Frame in the stack

Format accepts flags that alter the printing of some verbs, as follows:

%+v   Prints filename, function, and line number for each Frame in the stack.

func (*StackTrace) Initialize added in v0.2.0

func (st *StackTrace) Initialize()

Initialize initializes the StackTrace with the callers of the current func

Jump to

Keyboard shortcuts

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