Lovin' your errors
How a little TLC pays back with interest.
Roger Peppe
Canonical Ltd
Roger Peppe
Canonical Ltd
if err != nil { return err }
func doSomething() { foo() bar() baz() }
func doSomething() error { if err := foo(); err != nil { return err } if err := bar(); err != nil { return err } if err := baz(); err != nil { return err } return nil }
func doSomething() { foo() bar() baz() }
// MustCompile is like Compile but panics if the expression cannot be parsed. // It simplifies safe initialization of global variables holding compiled regular // expressions. func MustCompile(str string) *Regexp { regexp, error := Compile(str) if error != nil { panic(`regexp: Compile(` + quote(str) + `): ` + error.Error()) } return regexp }
if err != nil { return err }
go get github.com/kisielk/errcheck % errcheck ./... agent/agent.go:654:11 buf.Write(data) agent/bootstrap.go:96:12 st.Close() agent/identity.go:29:12 os.Remove(c.SystemIdentityPath()) agent/tools/toolsdir.go:57:16 defer zr.Close()
// IncCounterAsync increases by one the counter associated with the composed // key. The action is done in the background using a separate goroutine. func (s *Store) IncCounterAsync(key []string) { s.Go(func(s *Store) { if err := s.IncCounter(key); err != nil { logger.Errorf("cannot increase stats counter for key %v: %v", key, err) } }) }
// Errors holds any errors encountered during the parallel run. type Errors []error func (errs Errors) Error() string { switch len(errs) { case 0: return "no error" case 1: return errs[0].Error() } return fmt.Sprintf("%s (and %d more)", errs[0].Error(), len(errs)-1) }
var ErrNotFound = errors.New("not found") err := environments.Find(bson.D{{"_id", id}}).One(&env) if err == mgo.ErrNotFound { return nil }
type PathError struct { Op string Path string Err error } func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() } err := os.Create("/tmp/something") if err, ok := err.(*os.PathError); ok { }
type Error interface { error Timeout() bool // Is the error a timeout? Temporary() bool // Is the error temporary? } if err, ok := err.(net.Error); ok && err.Temporary() { ... }
func IsNotExist(err error) bool { switch pe := err.(type) { case nil: return false case *PathError: err = pe.Err case *LinkError: err = pe.Err } return err == syscall.ENOENT || err == ErrNotExist }
if err != nil { return "", fmt.Errorf("cannot read random secret: %v", err) }
for { select { case msg := <-msgChan: err := doSomething(msg.params) msg.reply <- fmt.Errorf("cannot do something: %v", err) ... } }
"cannot read random secret: unexpected EOF"
cannot get login entity: cannot get user "admin": mongo query failed: cannot acquire socket: cannot log in: error authorizing user "admin": request failed: cannot read reply: EOF
err := fmt.Errorf("cannot open file: %v", err) if os.IsNotExist(err) { // never reached }
if err != nil { return errgo.Notef(err, "cannot read random secret") }
if errgo.Cause(err) == io.UnexpectedEOF { ... } if os.IsNotExist(errgo.Cause(err)) { ... }
return errgo.Mask(err)
// Preserve any cause return errgo.Mask(err, errgo.Any) // Preserve only some causes return errgo.Mask(err, os.IsNotExist, os.IsPermission)
return errgo.NoteMask(err, "cannot open database file", os.IsNotExist)
if err == mgo.IsNotFound { return errgo.WithCausef(err, params.ErrNotFound, "no such document") }
fmt.Printf("%v\n", err) cannot encrypt password: cannot read random secret: unexpected EOF fmt.Printf("%#v", err) [{/home/rog/src/github.com/juju/utils/encrypt.go:97: cannot encrypt password} {/home/rog/src/github.com/juju/utils/password.go:32: cannot read random secret} {unexpected EOF}]