Skip to content

Instantly share code, notes, and snippets.

@pwmcintyre
Created November 6, 2019 10:53
Show Gist options
  • Save pwmcintyre/5b29e07c857b14ca1d281587f00abb2b to your computer and use it in GitHub Desktop.
Save pwmcintyre/5b29e07c857b14ca1d281587f00abb2b to your computer and use it in GitHub Desktop.

Golang doesn't have try/catch blocks, so you can't simply "throw" an error and hope something will catch it and give you a stack-trace showing you where it came from. Instead we return errors and check them ... but it's important to introduce context before returning ... here's why

Here a simple go program I wrote which doesn't appear to work 🤔

$ go run main.go 
access denied

... it attempts to "process" and "save", but since the "process" function adds no context to the error (it just bubbles it up), the final error is very confusing!

Here's the code:

package main

import (
	"strings"
	"fmt"
	"github.com/pkg/errors"
)

func main() {
	err := process("Hello, World!")
	if err != nil {
		fmt.Println(err) // log errors
	}
}

func process(words string) error {

	// process
	data := strings.ToUpper(words)

	// attempt to persist
	err := persist(data)
	if err != nil {
		return err
	}

	return nil
}

func persist(data string) error {
	return errors.New("access denied")
}

This can be resolved with a single change -- using errors.Wrap() to give context to our underlying errors:

func process(words string) error {

	...

		// return err
		return errors.Wrap(err, "failed to persist") // <--- wrap in context: "what it failed to do"

    ...

}

Now we get a more context-aware error, and if this was in a log i would know what the program was doing when it failed -- it was trying to persist

$ go run main.go 
failed to persist: access denied

The exception to this is if you're intentially trying to avoid leaking your underlying implementation details

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment