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

Custom Error Types

A custom error type is like designing your own error form with extra fields, so the code that receives it can read more than just a message -- it can check exactly what kind of problem happened.

Defining a Custom Error Type

A custom error is just a struct with an Error() string method, which lets it carry additional structured fields beyond a plain message -- useful when calling code needs more context than text alone.

Example: Defining a Custom Error Type

markup
package main

import "fmt"

type ValidationError struct {
	Field string
	Msg   string
}

func (e *ValidationError) Error() string {
	return fmt.Sprintf("%s: %s", e.Field, e.Msg)
}

func main() {
	var err error = &ValidationError{Field: "age", Msg: "must be positive"}
	fmt.Println(err)
}

Returning a Custom Error

A function can return a custom error type through the standard error interface, so calling code that only cares whether it failed can treat it like any other error, while code that wants details can inspect it further.

Example: Returning a Custom Error

markup
package main

import "fmt"

type OutOfStockError struct {
	Item string
}

func (e *OutOfStockError) Error() string {
	return fmt.Sprintf("%s is out of stock", e.Item)
}

func checkStock(item string, qty int) error {
	if qty <= 0 {
		return &OutOfStockError{Item: item}
	}
	return nil
}

func main() {
	if err := checkStock("widget", 0); err != nil {
		fmt.Println(err)
	}
}

Extracting a Custom Error with errors.As

errors.As checks whether an error (or anything it wraps) matches a specific custom error type, and if so, populates a target variable with it -- letting calling code react to structured fields, not just a message string.

Note: errors.As also unwraps any chain of wrapped errors to find a matching type.

Example: Extracting a Custom Error with errors.As

markup
package main

import (
	"errors"
	"fmt"
)

type OutOfStockError struct {
	Item string
}

func (e *OutOfStockError) Error() string {
	return fmt.Sprintf("%s is out of stock", e.Item)
}

func main() {
	var err error = &OutOfStockError{Item: "widget"}

	var oosErr *OutOfStockError
	if errors.As(err, &oosErr) {
		fmt.Println("out of stock item:", oosErr.Item)
	}
}
Common Mistakes
  1. Defining a custom error struct but forgetting to implement Error() string on it, so it doesn't actually satisfy the error interface.
  2. Using a value receiver for Error() but returning &MyError{} (a pointer) elsewhere inconsistently, causing type assertion mismatches.
  3. Storing only a string message in a custom error type when structured fields (like a status code) would let callers react programmatically.
Chapter Summary
  • A custom error type is any struct that implements the Error() string method.
  • Custom errors can carry structured data beyond a plain message, like an error code or the invalid value.
  • Callers use errors.As to check for and extract a specific custom error type.
  • Custom errors make failure handling more precise than parsing error message strings.
🔒

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.