0
0
GoHow-ToBeginner · 4 min read

How to Wrap Error in Go: Simple Guide with Examples

In Go, you can wrap errors using fmt.Errorf with the %w verb or the errors.Wrap function from external packages. Wrapping adds context to the error while preserving the original error for inspection.
📐

Syntax

Use fmt.Errorf with %w to wrap an existing error with a new message. The %w verb tells Go to wrap the original error inside the new one.

Example syntax:

fmt.Errorf("new message: %w", originalError)
go
err := errors.New("original error")
wrappedErr := fmt.Errorf("additional context: %w", err)
💻

Example

This example shows how to wrap an error returned from a function and then check the original error using errors.Is.

go
package main

import (
	"errors"
	"fmt"
)

func readFile() error {
	return errors.New("file not found")
}

func loadConfig() error {
	err := readFile()
	if err != nil {
		return fmt.Errorf("loadConfig failed: %w", err)
	}
	return nil
}

func main() {
	err := loadConfig()
	if err != nil {
		fmt.Println("Error:", err)
		if errors.Is(err, errors.New("file not found")) {
			fmt.Println("Cause: file not found error detected")
		} else {
			fmt.Println("Cause: unknown error")
		}
	}
}
Output
Error: loadConfig failed: file not found Cause: unknown error
⚠️

Common Pitfalls

A common mistake is to wrap errors without using %w, which prevents unwrapping and checking the original error.

Also, comparing errors directly with == often fails because wrapped errors are different objects.

go
package main

import (
	"errors"
	"fmt"
)

func badWrap() error {
	err := errors.New("original error")
	// Wrong: no %w, so error is not wrapped properly
	return fmt.Errorf("context: %v", err)
}

func goodWrap() error {
	err := errors.New("original error")
	// Correct: %w wraps the error
	return fmt.Errorf("context: %w", err)
}

func main() {
	origErr := errors.New("original error")
	badErr := badWrap()
	goodErr := goodWrap()

	fmt.Println("badWrap error:", badErr)
	fmt.Println("goodWrap error:", goodErr)

	// This will be false because badWrap does not wrap properly
	fmt.Println("badWrap is original error:", errors.Is(badErr, origErr))

	// This will be false too because errors.New creates a new error instance
	// Correct way is to save original error in a variable

	wrappedErr := fmt.Errorf("context: %w", origErr)
	fmt.Println("goodWrap is original error:", errors.Is(wrappedErr, origErr))
}
Output
badWrap error: context: original error goodWrap error: context: original error badWrap is original error: false goodWrap is original error: true
📊

Quick Reference

  • Wrap error: fmt.Errorf("message: %w", err)
  • Check error: errors.Is(err, targetErr)
  • Retrieve original error: errors.Unwrap(err)

Key Takeaways

Use fmt.Errorf with %w to wrap errors and preserve the original error.
Always use errors.Is to check if an error wraps a specific original error.
Avoid wrapping errors without %w as it breaks error unwrapping.
Store original errors in variables to compare correctly with errors.Is.
Wrapping errors adds helpful context for debugging while keeping error chains intact.