Day 9 - Error Handling
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
- Using built-in error handling (standard approach)
- 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
Dividefunction 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
errorinterface via theError()method. errors.As()helps extract and use detailed error information.
Summary (Key Takeaways)
| Concept | Explanation |
| Errors in Go | Errors are values, not exceptions |
| Built-in errors | Use errors.New() or fmt.Errorf() |
| Custom errors | Implement 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()?
| Function | Purpose | Example Use |
errors.Is() | Compares an error to a known predefined error | errors.Is(err, ErrDivideByZero) |
errors.As() | Extracts a specific custom error type and assigns it to a variable | errors.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.