errors

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2022 License: MPL-2.0 Imports: 2 Imported by: 4

README

errors

codecov GoDoc Go Report Card

Package errors implements a stdlib-compatible way of wrapping more than one error into an error chain, while supporting errors.Is and errors.As (and obviously Error() and Unwrap()), thus being a drop in replacement for other error types. Errors also provides all the stdlib functions, so you don't need to include both.

The Standard Library allows you to wrap exactly ONE error with eg fmt.Errorf, and will bail out if there are more than one %w receiver.

errors.Wrap will solve that by allowing arbitrary errors to be wrapped without losing information.

This is useful e.g. when collecting errors from several running go routines that might return a bunch of different errors.

Another slightly construed use case could be a situation where a bunch of different functions are called, and if failing, returns a common error that is handled further up the stack:

if err := someFunc(); err != nil {
	// MyError is handled up the stack
	return MyError
}

Up the stack, you don't want to check for any possible error. You just know that if you get MyError, you're handling things one way, and if you get any other error, you handle it differently. But this approach, while convenient, discards information about the actual error, though. Now, normally, you'd log it at the source at the risk of it being logged again later, or do something like:

return fmt.Errorf("%s: %w", err, MyError)

And while this wraps MyError, it doesn't wrap the actual error from `someFunc, which we might be interested in as well, maybe because some specific error requires specific handling:

So, if the error above was e.g. mysql.ErrNotFound, errors.Is(err, mysql.ErrNotFound) would be false, even if errors.Is(err, MyError) is true.

Instead, using errors.Wrap:

if err := someFunc(); err != nil {
	// MyError is handled explicitly up the stack
	return errors.Wrap(err, MyError)
}

This will make errors.Is return true for both, as they are now both properly wrapped.

Unwrap and Wrap both run in O(n) time, where n is the number of errors added to the chain.

Functions

func Wrap

func Wrap(errs ...error) error

Wrap will wrap one or more errors into a single error chain, compatible with errors.As and errors.Is. Note that if you're using this as a sort of append analogue (err = Wrap(err, ErrAnother) or similar, where the result overwrites the argument), then you should protect accordingly with appropriate synchronization measures (e.g. a mutex), just as you would with append.


Readme created from Go doc with goreadme

Documentation

Overview

Package errors implements a stdlib-compatible way of wrapping more than one error into an error chain, while supporting `errors.Is` and `errors.As` (and obviously `Error()` and `Unwrap()`), thus being a drop in replacement for other error types. Errors also provides a `New()` function which works like the stdlib version.

The Standard Library allows you to wrap exactly ONE error with eg `fmt.Errorf`, and will bail out if there are more than one `%w` receiver.

`errors.Wrap` will solve that by allowing arbitrary errors to be wrapped without losing information.

A construed (well, kinda) could be a situation where a bunch of different functions are called, and if failing, returns a common error that is handled further up the stack:

```golang

if err := someFunc(); err != nil {
	// MyError is handled up the stack
	return MyError
}

```

This discards information about the actual error, though. Now, normally, you'd do something like:

```golang

return fmt.Errorf("%s: %w", err, MyError)

```

And while this wraps `MyError`, it doesn't wrap the actual error from `someFunc, which we might be interested in as well, maybe because some specific error requires specific handling:

So, if the error above was e.g. `mysql.ErrNotFound`, `errors.Is(err, mysql.ErrNotFound)` would be false, even if `errors.Is(err, MyError)` is true.

Instead, using `errors.Wrap`:

```golang

if err := someFunc(); err != nil {
	// MyError is handled explicitly up the stack
	return errors.Wrap(err, MyError)
}

```

This will make `errors.Is` return true for both, as they are now both properly wrapped.

`Unwrap` and `Wrap` both run in O(n) time, where n is the number of errors added to the chain.

Index

Examples

Constants

This section is empty.

Variables

View Source
var Separator = ": "

Separator between errors in the chain when they're output together with `.Error()`. Can be overridden globally by setting this value, default is ": ".

Functions

func As

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

As is a wrapper around the stdlib function, so you don't need to import both packages

Example
package main

import (
	"fmt"
	"io/fs"
	"os"

	"github.com/adamhassel/errors"
)

func main() {
	if _, err := os.Open("non-existing"); err != nil {
		var pathError *fs.PathError
		if errors.As(err, &pathError) {
			fmt.Println("Failed at path:", pathError.Path)
		} else {
			fmt.Println(err)
		}
	}

}
Output:

Failed at path: non-existing

func Is

func Is(err, target error) bool

Is is a wrapper around the stdlib function, so you don't need to import both packages

Example
package main

import (
	"fmt"
	"io/fs"
	"os"

	"github.com/adamhassel/errors"
)

func main() {
	if _, err := os.Open("non-existing"); err != nil {
		if errors.Is(err, fs.ErrNotExist) {
			fmt.Println("file does not exist")
		} else {
			fmt.Println(err)
		}
	}

}
Output:

file does not exist

func New

func New(text string) error

New is a wrapper around the stdlib errors.New function, so you don't need to import both

Example
package main

import (
	"fmt"

	"github.com/adamhassel/errors"
)

func main() {
	err := errors.New("emit macho dwarf: elf header corrupted")
	if err != nil {
		fmt.Print(err)
	}
}
Output:

emit macho dwarf: elf header corrupted
Example (Errorf)

The fmt package's Errorf function lets us use the package's formatting features to create descriptive error messages.

package main

import (
	"fmt"
)

func main() {
	const name, id = "bimmler", 17
	err := fmt.Errorf("user %q (id %d) not found", name, id)
	if err != nil {
		fmt.Print(err)
	}
}
Output:

user "bimmler" (id 17) not found

func Unwrap

func Unwrap(err error) error

Unwrap is a wrapper around the stdlib function, so you don't need to import both packages

func Wrap

func Wrap(errs ...error) error

Wrap will wrap one or more errors into a single error chain, compatible with errors.As, errors.Is. Note that if you're using this as a sort of `append` analogue (`err = Wrap(err, ErrAnother)` or similar, where the result overwrites the argument), then you should protect accordingly with appropriate synchronization measures (e.g. a mutex), just as you would with `append`.

Types

This section is empty.

Jump to

Keyboard shortcuts

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