Skip to content

How to Handle Errors in Golang

Error handling in Go is a fundamental aspect of writing robust and reliable programs. Go does not have exceptions like some other languages (e.g., Python, Java). Instead, it uses explicit error handling, where functions that can fail return an error type as their last return value.

Basic Error Handling

In Go, errors are represented by the error interface, which is defined as:

type error interface {
    Error() string
}

This interface has a single method Error() that returns a string describing the error. When a function encounters an error, it can return an error value to indicate that something went wrong. For example:

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

In the above example, the divide function returns an error if the second argument b is zero, indicating a division by zero error.

To handle errors returned by a function, you can use the if statement to check if the error is nil (i.e., no error occurred) and handle it accordingly. For example:

result, err := divide(10, 0)

if err != nil {
    fmt.Println("Error:", err)
    return
}

fmt.Println("Result:", result)

In this example, we call the divide function with arguments 10 and 0 and check if the error is nil. If an error occurs, we print the error message; otherwise, we print the result.

Custom Error Types

In addition to using the errors.New function to create simple error messages, you can define custom error types by implementing the error interface for your own types. This allows you to provide more context and information about the error. For example:

type MyError struct {
    Message string
}

func (e *MyError) Error() string {
    return e.Message
}

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, &MyError{Message: "division by zero"}
    }
    return a / b, nil
}

In this example, we define a custom error type MyError that includes a Message field. We implement the Error method for this type to satisfy the error interface. The divide function now returns a pointer to a MyError instance when a division by zero error occurs.

Error Wrapping

In more complex scenarios, you may want to wrap an existing error with additional context or information. The errors package in Go provides the Wrap function to wrap an error with a message. For example:

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.Wrap(errors.New("division by zero"), "divide")
    }
    return a / b, nil
}

In this example, we use the Wrap function to wrap the error returned by errors.New("division by zero") with the message "divide". This allows us to provide more context about where the error occurred.

Unwrapping Errors

To extract the original error from a wrapped error, you can use the Unwrap function provided by the errors package. This function returns the original error that was wrapped. For example:

err := divide(10, 0)

if err != nil {
    if errors.Is(err, &MyError{}) {
        fmt.Println("Custom error:", err)
    } else {
        fmt.Println("Error:", err)
    }

    if wrappedErr := errors.Unwrap(err); wrappedErr != nil {
        fmt.Println("Original error:", wrappedErr)
    }
}

In this example, we check if the error is of type MyError using the errors.Is function. If it is, we print the custom error message. We then use the Unwrap function to extract the original error and print it.