Skip to main content

Command Palette

Search for a command to run...

Day 9 - Error Handling

Published
4 min read

Introduction

Error handling is a fundamental concept in Go (Golang) used to ensure reliability, debuggability, and robustness in applications. In Go, errors are treated as values, making error handling explicit and predictable.


Types of Error Handling in Go

  1. Using built-in error handling (standard approach)
  2. Using custom error types (advanced/customized approach)

Why is Error Handling Important?

Error handling is essential in software development to catch unexpected failures and respond appropriately.

Real-Life Example

Suppose you're building a backend application that connects to MongoDB. Even if your logic is correct, there might be a mistake in the MongoDB URI or the database server might be down:

client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
    fmt.Printf("Error connecting to Database: %v", err)
}

Without error handling, the program may fail silently.
With proper error handling, debugging becomes faster and the system becomes more reliable.


Error Handling Using Built-in Methods

Unlike Java, C++, or Python, Go does not use try/catch. Instead, errors are returned as values.

The error Interface

type error interface {
    Error() string
}

Any type that implements the Error() method returning a string is considered an error.


Creating Errors (Built-in Approaches)

Using the errors package

package main

import "errors"

func ReturnError() error {
    return errors.New("This is a new error")
}

Using the fmt package

func ReturnError2() error {
    return fmt.Errorf("This is another error")
}

The default value of error is nil, which means no error.


Example: Dividing Two Numbers

package main

import (
    "errors"
    "fmt"
)

var ErrDivideByZero = errors.New("denominator should not be zero")

func Divide(a, b int) (int, error) {
    if b == 0 {
        return 0, ErrDivideByZero
    }
    return a / b, nil
}

func main() {
    a, b := 10, 0
    result, err := Divide(a, b)
    if err != nil {
        switch {
        case errors.Is(err, ErrDivideByZero):
            fmt.Println("Divide by zero error")
        default:
            fmt.Printf("Unexpected division error: %s
", err)
        }
        return
    }
    fmt.Printf("%d / %d = %d
", a, b, result)
}

Explanation:

  • The Divide function returns both the result and an error.
  • Errors are checked using if err != nil.
  • errors.Is() checks if a specific error is returned.

Custom Error Handling in Go

When built-in errors are not enough, you can create custom errors using your own struct.

Example: Custom Error

package main

import (
    "errors"
    "fmt"
)

type CustomError struct {
    A   int
    B   int
    Msg string
}

func (c *CustomError) Error() string {
    return c.Msg
}

func Divide(a, b int) (int, error) {
    if b == 0 {
        return 0, &CustomError{A: a, B: b, Msg: "Cannot divide by zero"}
    }
    return a / b, nil
}

func main() {
    if val, err := Divide(3, 0); err != nil {
        var customErr *CustomError
        switch {
        case errors.As(err, &customErr):
            fmt.Printf("%d / %d is not mathematically valid: %s
",
                customErr.A, customErr.B, customErr.Error())
        default:
            fmt.Printf("Unexpected division error: %s
", err)
        }
        return
    } else {
        fmt.Println(val)
    }
}

Output:

3 / 0 is not mathematically valid: Cannot divide by zero

Summary:

  • A custom struct (CustomError) is used.
  • It implements the error interface via the Error() method.
  • errors.As() helps extract and use detailed error information.

Summary (Key Takeaways)

ConceptExplanation
Errors in GoErrors are values, not exceptions
Built-in errorsUse errors.New() or fmt.Errorf()
Custom errorsImplement the error interface for more context

❓ Frequently Asked Questions (FAQs)

1️ Why doesn't Go use try/catch like other languages?

Go's philosophy emphasizes simplicity and explicit error handling. By returning errors as values, Go encourages developers to handle errors immediately and avoid hidden runtime exceptions.

2️ What is the difference between errors.Is() and errors.As()?

FunctionPurposeExample Use
errors.Is()Compares an error to a known predefined errorerrors.Is(err, ErrDivideByZero)
errors.As()Extracts a specific custom error type and assigns it to a variableerrors.As(err, &customErr)

3️ What is the zero value of an error in Go?

The zero value of an error is nil, which represents "no error".

4️ When should I create custom errors?

Custom errors are useful when you want to attach additional information (e.g., parameters, context, or user-friendly messages).

5️ Can we wrap errors in Go?

Yes, using fmt.Errorf("message: %w", err) you can wrap an existing error to add more context.

More from this blog

G

GoSprint90

16 posts

Welcome to GoQuest90 — a 90-day journey from absolute beginner to confident Go developer.