Error Handling #
gFly Provides several default errors in the core/errors
directory. However, you can absolutely create additional types of errors you want and should be placed in the app/errors
folder
// Create new error from Go package
errors.New("wrong user email address or password")
// Use error Unauthorized from app/core/errors
errors.Unauthorized
In Go, error handling is approached differently than in other languages, emphasizing explicit error handling and avoiding exceptions. So, we encourage you to read and understand the 5 ways below to create errors and handle them better in your application.
- The Basics of Error Handling in Go
- Error Propagation and Centralized Handling
- Error Wrapping and Context
- Error Handling Libraries and Tools
- Handling Panics and Recovering
The Basics of Error Handling in Go #
This approach of returning errors explicitly and checking them using conditional statements is idiomatic in Go
It emphasizes clear and concise error handling, ensuring that errors are not ignored and are dealt with appropriately.
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 2)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Result:", result)
}
Error Propagation and Centralized Handling #
When a function encounters an error, it can propagate the error up the call stack instead of handling it immediately
Finally, in the main function, we check the error and handle it centrally
func operationA() error {
// Perform some operation
return operationB()
}
func operationB() error {
// Perform some operation
return operationC()
}
func operationC() error {
// Perform some operation
return fmt.Errorf("an error occurred")
}
func main() {
if err := operationA(); err != nil {
log.Println("Error:", err)
// Handle or log the error centrally
}
}
Error Wrapping and Context #
Error wrapping and context provide valuable information for debugging and troubleshooting.
By wrapping an error with additional context, you can provide more detailed information about the error’s origin and the surrounding circumstances
func readFile() error {
data, err := ioutil.ReadFile("file.txt")
if err != nil {
return fmt.Errorf("failed to read file: %w", err)
}
// Process the file data
return nil
}
func main() {
if err := readFile(); err != nil {
log.Println("Error:", err)
// Handle or log the error
}
}
When the error is logged or handled in the main function, the additional context can be extracted using the %v
verb or the errors.Unwrap
function to reveal the underlying error.
By wrapping errors and adding context, you can create a chain of errors that provides a clear picture of the error’s origin and the actions leading up to it, enabling better troubleshooting and understanding of the error scenarios.
Error Handling Libraries and Tools #
There are several error handling libraries and tools available in Go that can help streamline error handling and enhance the developer experience. These libraries provide additional features and utilities to simplify error management.
One such library is "pkg/errors"
(
https://github.com/pkg/errors), which provides functions like errors.Wrap
and errors.WithMessage
for error wrapping and context propagation.
Another popular library is "go-errors/errors"
(
https://github.com/go-errors/errors), which introduces the Error type that allows capturing stack traces along with errors, making it easier to identify the exact location where an error occurred.
Additionally, tools like "errcheck"
(
https://github.com/kisielk/errcheck) and "goerrcheck"
(
https://github.com/dominikh/goerrcheck) analyze Go code to identify unchecked errors, ensuring comprehensive error handling.
These libraries and tools offer powerful capabilities for error handling and enable developers to effectively manage errors, propagate context, and capture valuable diagnostic information, ultimately improving the overall reliability and maintainability of Go applications.
Handling Panics and Recovering #
In Go, panics are exceptional situations that can occur at runtime. While it’s generally recommended to handle errors gracefully, there are scenarios where panics may occur, such as out-of-bounds array access or nil pointer dereference.
To handle panics, Go provides the recover()
function, which allows you to capture and handle a panic, preventing it from terminating the program.
func recoverFromPanic() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}
func doSomething() {
defer recoverFromPanic()
// Code that may cause a panic
// If a panic occurs, execution will continue here
// after the recovery function is called.
panic("panic!!")
}
func main() {
doSomething()
fmt.Println("Program continues to execute...")
}
By using defer
and recover()
, you can gracefully recover from panics and handle them in a controlled manner, allowing your program to continue running without abruptly terminating.
Refer https://dev.to/dsysd_dev/demystifying-error-handling-in-go-best-practices-and-beyond-272f