ProgrammingGo Developer

How is error handling implemented in Go: what approaches to handling exist, why are errors usually returned instead of thrown, and how can custom error types be implemented?

Pass interviews with Hintsage AI assistant

Answer.

In Go, the standard approach to error handling is by returning a value of type error from functions. Unlike languages with exceptions, in Go exceptions (panic, recover) are used only for truly exceptional situations; for business logic, regular errors should be used.

The classic way:

func doSomething() error { // ... return nil // or errors.New("some error") } err := doSomething() if err != nil { // handle error }

You can create custom error types for more detailed analysis:

type MyError struct { Code int Message string } func (e *MyError) Error() string { return fmt.Sprintf("(%d) %s", e.Code, e.Message) } err := &MyError{404, "not found"}

Typical check for a specific error:

if myErr, ok := err.(*MyError); ok && myErr.Code == 404 { // handle 404 error }

Trick question.

Can you compare error to nil using == in Go?

Answer: Yes, you can and should do this to check for the absence of an error. However, it's important to remember: if the error has been wrapped or created using errors containing nil inside structs, then the comparison might be incorrect. For example:

var err error = (*MyError)(nil) fmt.Println(err == nil) // false!

An error is not equal to nil because the interface is not nil if its type is not nil, even if the value inside is nil.

Examples of real errors due to unawareness of the nuances of the topic.


Story

A microservice was logging errors by comparing to nil. One developer returned a typed error like (*MyError)(nil), not noticing that this is not equivalent to nil (the interface is not nil). As a result, error handling stopped working, and many false alerts were logged.


Story

In a project, instead of passing errors along the chain, they used panic for all errors, considering this a "clean" way. This led to the application crashing on every invalid user input, as panic/recover are not meant for streaming business logic.


Story

An error was wrapped several times using fmt.Errorf("some: %w", err), and when checking for a specific error type, they performed a regular comparison instead of using errors.Is and errors.As. This led to business logic not reacting to custom error types, even though they were indeed present within the wrapped error.