← Back to Go Course | Chapter 9: Error Handling | Lesson 1 of 6

The error Interface

An error in Go is just a small box that can hold a message explaining what went wrong -- and every function that might fail hands one back for you to check.
Syntax
go
type error interface {
    Error() string
}

err := errors.New("message")
if err != nil {
    // handle error
}

The error Interface Itself

Go's built-in error type is just an interface with a single method, Error() string. Any type that implements this method can be used as an error, which keeps error handling simple and uniform across the whole language.

Example: The error Interface Itself

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the fmt package
import "fmt"

// Define a struct type named MyError
type MyError struct {
	Msg string
}

// Define the method Error on type MyError
func (e *MyError) Error() string {
	// Send e.Msg back to the caller
	return e.Msg
}

// main is where the program starts running
func main() {
	var err error = &MyError{Msg: "something went wrong"}
	// Print the values followed by a newline
	fmt.Println(err)
}

Creating Errors with errors.New

The simplest way to produce an error is errors.New("message"), which returns a basic error value holding that static text -- ideal for straightforward failure conditions.

Example: Creating Errors with errors.New

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the packages this program uses
import (
	"errors"
	"fmt"
)

// Define the function checkAge
func checkAge(age int) error {
	// Check whether age < 0
	if age < 0 {
		return errors.New("age cannot be negative")
	}
	// Send nil back to the caller
	return nil
}

// main is where the program starts running
func main() {
	// Check whether err := checkAge(-5); err != nil
	if err := checkAge(-5); err != nil {
		// Print the values followed by a newline
		fmt.Println("error:", err)
	}
}

Creating Errors with fmt.Errorf

fmt.Errorf builds an error using Printf-style formatting, letting you embed dynamic values directly into the error message without a separate Sprintf call.

Note: fmt.Errorf is generally preferred over errors.New when the message needs any dynamic data.

Example: Creating Errors with fmt.Errorf

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the fmt package
import "fmt"

// Define the function checkStock
func checkStock(item string, qty int) error {
	// Check whether qty <= 0
	if qty <= 0 {
		return fmt.Errorf("item %q is out of stock", item)
	}
	// Send nil back to the caller
	return nil
}

// main is where the program starts running
func main() {
	// Run this block only if the condition is true
	if err := checkStock("widget", 0); err != nil {
		// Print the values followed by a newline
		fmt.Println(err)
	}
}

The if err != nil Idiom

The standard Go pattern is to check the error result immediately after a call that might fail, and handle or propagate it before proceeding -- this makes failure paths explicit and impossible to silently skip.

Example: The if err != nil Idiom

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the packages this program uses
import (
	"fmt"
	"strconv"
)

// main is where the program starts running
func main() {
	// Short declaration: create n, err and infer the type
	n, err := strconv.Atoi("not-a-number")
	// Handle the error if one occurred
	if err != nil {
		// Print the values followed by a newline
		fmt.Println("failed to parse:", err)
		return
	}
	// Print the values followed by a newline
	fmt.Println("parsed:", n)
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Ignoring a returned error entirely (using _ or just not checking it) instead of handling or propagating it.
  2. Comparing errors with == when they were created dynamically, instead of using errors.Is for wrapped errors.
  3. Assuming errors.New(fmt.Sprintf(...)) is idiomatic instead of using fmt.Errorf directly, which supports %w for wrapping.
Chapter Summary
  • error is a built-in interface requiring one method: Error() string.
  • Functions that can fail conventionally return their result plus an error as the last return value.
  • errors.New and fmt.Errorf are the two common ways to create a simple error.
  • Checking 'if err != nil' immediately after a call is the standard Go error-handling idiom.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.