Golang return error and handle [Best Practices]


GOLANG Solutions, GO

In this article, we shall be discussing how to return and handle errors effectively using custom and inbuilt Golang functions, with help of practical examples.

 

Golang return error

An error is basically a fault that occurs in a program execution flow. These errors can be of various natures:- Caused by programmers through code syntax and interface errors , system-related Resources and Runtime errors, algorithm-related logic and arithmetic errors. Which later are solved through debugging process.

In Golang ,The Error is an interface that holds Error() string method. Its implemented as follows

type error interface {
Error() string
}

In an nutshell, when the Error() method is called, it's return value is in form of string datatype. Through the use of inbuilt Go functions of the fmt and errors packages, we can construct the kind of error message to be displayed. Below is an example to construct Errors using fmt.Error() in Golang, i.e you want to read a file from a given path, unfortunate the file doesn't exist or the path given is invalid. For example:=

package main

import (
	"fmt"
	"os"
)

func ReadFile(file string) error {
	dataFile, err := os.ReadFile(file)
	if err != nil {
		return fmt.Errorf("An error occurred while Reading the file: open : %v", err)
	}
	fmt.Println(string(dataFile))
	return nil
}
func main() {
	resultsErr := ReadFile("")
	if resultsErr != nil {
		fmt.Printf("%v", resultsErr)
	}
}

Output:

With the file attached ensure you replace the ReadFile("test.txt")

$ go run main.go
Hello

without file attached

$ go run main.go
An error occurred while Reading the file: open: no such file or directory

Explanation:- In the above code, ReadFile() error{} function returns an error which is nil whenever no error encountered. In Golang, the Error return value is nil as the default, or “zero”. Notice that checking if err != nil{} is the idiomatic way to determine if an error was encountered in Golang syntax, in this function we are returning the error only, handling the file data within the function. fmt.Error() enables us to customize the kind of message to be displayed. These messages are always in a lowercase format and don't end with punctuation.

In Golang there are numerous ways to return and handle errors Namely:=

  • Casting Errors
  • Error wrapping mechanism
  • Panic, defer and recover

 

Different methods of error handling in Go Func

Method 1:- Casting Errors

Casting errors is a way of defining custom and expected errors, with golang we can make use of erros.Isand errors.As() error functions to cast different types of errors. i.e,errors.Is we create a custom error of a particular type and check If the error matches the specific type the function will return true, if not it will return false.

package main

import (
	"errors"
	"fmt"
	"io/fs"
	"os"
)

var fileNotFound = errors.New("The file doesn't  exist")

func ReadFile(file string) error {
	dataFile, readErr := os.ReadFile(file)
	if readErr != nil {
		if errors.Is(readErr, fs.ErrNotExist) {
			return fmt.Errorf("this fileName %s  doesn't exist ", file)
		} else {
			return fmt.Errorf("Error  occured while opening the file : %w", readErr)
		}
	}
	fmt.Println(string(dataFile))
	return nil
}
func main() {
	fileName := os.Args[1]
	if fileName != "" {
		resultsError := ReadFile(fileName)
		if resultsError != nil {
			fmt.Printf("%v", resultsError)
		}
	} else {
		fmt.Println("the file name cant be empty")
	}
}

Output:

$ go run main.go "new"
this fileName new  doesn't exist

Explanation:- We are using errors.Is(readErr, fs.ErrNotExist) {} to check if the file passed exist, if it doesn't exist we return custom message as shown above. we can also use the custom error message such as errors.New() to create expected error and handle it as errors.Is(readErr, fileNotFound) {} the return values will be the same.

 

Method 2:- Error wrapping

Wrapping is a way of using other errors within a function to provide more context and detailed error messages.

fmt.Error() function enable us to create a wrapped errors with use of %w flag. The %w flag is used for inspecting and unwrapping errors.
In this subtitles we can incorporate other functions from errors package used to handle errors, namely:- errors.As, errors.Is, errors.Unwrap functions. errors.As is used to cast a specific error type, i.e func As(err error, target any) bool{}, also, the errors.Unwrap is used to inspect and expose the underlying errors in a program,i.e func (e *PathError)Unwrap()error{ return e.Err}, Furthermore the errors.Is mostly for comparing error value against the sentinel value if is true or false, i.e func Is(err,target error) bool{}.

Example of Error Wrapping

package main

import (
	"errors"
	"fmt"
	"os"
)

func ReadFile(file string) error {
	dataFile, readErr := os.ReadFile(file)
	var pathError *os.PathError
	if readErr != nil {
		if errors.As(readErr, &pathError) {
			return fmt.Errorf("this fileName %s  doesn't exist and failed  opening file at this path %v", file, pathError.Path)
		}
		return fmt.Errorf("Error  occured while opening the file : %w", readErr)

	}
	fmt.Println(string(dataFile))
	return nil
}
func main() {
	fileName := os.Args[1]
	if fileName != "" {
		resultsError := ReadFile(fileName)
		if resultsError != nil {
			fmt.Printf("%v", resultsError)
		}
	} else {
		fmt.Println("the file name can't be empty")
	}
}

Output:

With the file attached ensure you replace the ReadFile("test.txt")

$ go run main.go
Hello

without file attached

$ go run main.go ""
the file name can't be empty
$ go run main.go next.txt
this fileName news.txt  doesn't exist and failed opening file at this path news.txt

Explanation:- In the above code we have used fmt.Errorf() functions to format the error message to be displayed and wrapping error using a custom error message with wrap function errors.Is() which checks if the path exists. You can avoid unnecessary error wrapping and handle it once.

 

Method-3: Using Panic, Defer and Recover

We have covered this topic in detail in a separate article Golang panic handing [capture, defer, recover, log]

 

Summary

At this point in this article, you have learned various ways to return and handle errors in the Golang function. In Go, Errors are considered to be a very lightweight piece of data that implements the Error interface. Custom errors in Go help in debugging and signaling where the error has occurred from. Error tracing is easy as compared to other programming languages. Golang application development, error handling is very critical and helps one not only during debugging but also to monitor the application behavior. We recommend you to read more about panic, recover and defer mechanism of error handling as well.

 

References

error-handling in Go
Working with errors in golang
Errors

 

Deepak Prasad

Deepak Prasad

He is the founder of GoLinuxCloud and brings over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels in various domains, from development to DevOps, Networking, and Security, ensuring robust and efficient solutions for diverse projects. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment