Search⌘ K

Error-Handling and Panicking in a User-Defined Package

Explore how to implement error handling and panic recovery in custom Go packages. Learn to define error types, use panic and recover to handle errors gracefully, and return error values to callers for safer package boundaries.

We'll cover the following...

Here are a couple of best practices which every writer of custom packages should apply:

  • Always recover from panic in your package: no explicit panic() should be allowed to cross a package boundary.
  • Return errors as error values to the callers of your package.

This is nicely illustrated in the following code:

package parse
import (
	"fmt"
	"strings"
	"strconv"
)

// A ParseError indicates an error in converting a word into an integer.
type ParseError struct {
        Index int      // The index into the space-separated list of words.
        Word  string   // The word that generated the parse error.
        Err error      // The raw error that precipitated this error, if any.
}

// String returns a human-readable error message.
func (e *ParseError) String() string {
        return fmt.Sprintf("pkg parse: error parsing %q as int", e.Word)
}

// Parse parses the space-separated words in in put as integers.
func Parse(input string) (numbers []int, err error) {
        defer func() {
                if r := recover(); r != nil {
                        var ok bool
                        err, ok = r.(error)
                        if !ok {
                                err = fmt.Errorf("pkg: %v", r)
                        }
                }
        }()

        fields := strings.Fields(input)
        numbers = fields2numbers(fields)
        return
}

func fields2numbers(fields []string) (numbers []int) {
        if len(fields) == 0 {
                panic("no words to parse")
        }
        for idx, field := range fields {
                num, err := strconv.Atoi(field)
                if err != nil {
                        panic(&ParseError{idx, field, err})
                }
                numbers = append(numbers, num)
        }
        return
}

In parse.go, we implement a simple version of a parse package. From line 9 to line 13, we define a ParseError type (see the comments in the code for more info). Then, we have a String() ...