1 min read

Golang: Returning errors with context

Golang: Returning errors with context
Photo by David Pupaza / Unsplash

Usually in Golang, it is recommended that, while propagating errors outside, just return the error do not log it. This blog by Dave Cheney talks in length about how shall we handle logging and errors. But while returning/propagating errors, somtimes it becomes necessary to add the context of the error along with the actual error.

Basic example is:

Consider your web app is talking to another gRPC server for getting location information through a function called, GetLocationFor(user). Now there could be long enough function call tree that lands us onto this function. So if something goes wrong with gRPC connection, and if we return the error as is, technically we have lost the context.

func GetLocationFor(u *User) (*Location,error) {
	respMsg, err := grpcClient.GetLocationFor(u.name)
	if err != nil{
		// here we directly send the error
        return nil, err
	}
	// process the respMsg and move on
}

So there is one better way to return the error (without logging it) and keep the context:

Consider following the supporting method for creating error objects

func New(args ...interface{}) error {
    var err error
    var rawData []interface{}
    for _, arg := range args {
    	switch arg.(type) {
	    	case error:
    			err = arg.(error)
	 		  	log.Println("error", err)
			 	continue
	    	default:
    			rawData = append(rawData, arg)
        }
    }
    if err == nil {
    	err = errors.New(fmt.Sprintf("%v", rawData))
    }
    return errors.New(fmt.Sprintf("%v [error => %s]", rawData, err.Error()))
}

And use it as

import github.com/akshaydeo/errors

func GetLocationFor(u *User) (*Location,error){
	respMsg, err := grpcClient.GetLocationFor(u.name)
	if err != nil{
	// here we directly send the error
	return nil, errors.New("while getting location from grpc client in GetLocationFor", err)
	}
	// process the respMsg and move on
}

After this, whenver you log the error it will be something like while getting location from grpc client in GetLocatioFor [error => <original_error_message_from_grpc_client>]

This keeps the context of the error very specific and makes it easier to pinpoint the exact issue.

Happy coding \m/