Trace Error

Error wrapping with file, line, and function name using runtime.Caller.

package main

import (
	"errors"
	"fmt"
	"path/filepath"
	"runtime"
)

type TraceError struct {
	File string
	Func string
	Line int
	Err  error
}

func (e *TraceError) Error() string {
	return fmt.Sprintf("%s:%d:%s %s", e.File, e.Line, e.Func, e.Err.Error())
}

func (e *TraceError) Unwrap() error {
	return e.Err
}

func WrapError(err error) error {
	if err == nil {
		return nil
	}
	if _, ok := err.(*TraceError); ok {
		return err // avoid double wrapping
	}
	pc, file, line, ok := runtime.Caller(1)
	if !ok {
		return &TraceError{Err: err}
	}
	return &TraceError{
		File: filepath.Base(file),
		Func: filepath.Base(runtime.FuncForPC(pc).Name()),
		Line: line,
		Err:  err,
	}
}

// Sentinel errors
var ErrNotFound = errors.New("not found")
var ErrDuplicate = errors.New("duplicate")

func findBookmark(id string) error {
	return WrapError(fmt.Errorf("bookmark %s: %w", id, ErrNotFound))
}

func main() {
	err := findBookmark("abc-123")
	if err != nil {
		fmt.Println(err)
		// Check the underlying error
		if errors.Is(err, ErrNotFound) {
			fmt.Println("it's a not-found error")
		}
	}
}
▶ Open Go Playground

Copy the code above and paste to run

© 2026 ByteLearn.dev. Free courses for developers. · Privacy