Loading...
Loading...
Implement Go error handling patterns including error wrapping, sentinel errors, custom error types, and error handling conventions. Use when handling errors, creating error types, or implementing error propagation. Trigger words include "error", "panic", "recover", "error handling", "error wrapping".
npx skill4agent add armanzeroeight/fastagent-plugins error-handlingresult, err := doSomething()
if err != nil {
return fmt.Errorf("do something: %w", err)
}var ErrNotFound = errors.New("not found")
if errors.Is(err, ErrNotFound) {
// Handle not found
}func ReadFile(path string) ([]byte, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read file %s: %w", path, err)
}
return data, nil
}func Divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}func ProcessFile(path string) error {
data, err := ReadFile(path)
if err != nil {
return fmt.Errorf("process file: %w", err)
}
if err := Validate(data); err != nil {
return fmt.Errorf("validate data: %w", err)
}
return nil
}// Original error
err := os.Open("file.txt")
// Wrapped once
err = fmt.Errorf("open config: %w", err)
// Wrapped again
err = fmt.Errorf("initialize app: %w", err)
// Unwrap to check original
if errors.Is(err, os.ErrNotExist) {
// Handle file not found
}var (
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
ErrInvalidInput = errors.New("invalid input")
)
func GetUser(id string) (*User, error) {
user, ok := cache[id]
if !ok {
return nil, ErrNotFound
}
return user, nil
}user, err := GetUser("123")
if errors.Is(err, ErrNotFound) {
// Handle not found case
return nil
}
if err != nil {
// Handle other errors
return err
}type ValidationError struct {
Field string
Value interface{}
Msg string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation failed for %s: %s", e.Field, e.Msg)
}
func Validate(user *User) error {
if user.Email == "" {
return &ValidationError{
Field: "email",
Value: user.Email,
Msg: "email is required",
}
}
return nil
}if err := Validate(user); err != nil {
var valErr *ValidationError
if errors.As(err, &valErr) {
fmt.Printf("Field %s failed: %s\n", valErr.Field, valErr.Msg)
}
return err
}// Good
result, err := doSomething()
if err != nil {
return err
}
// Bad - don't defer error checking
result, err := doSomething()
// ... more code ...
if err != nil {
return err
}// Bad
doSomething()
// Good
if err := doSomething(); err != nil {
log.Printf("warning: %v", err)
}
// Or explicitly ignore
_ = doSomething()func LoadConfig() (*Config, error) {
data, err := readConfigFile()
if err != nil {
return nil, fmt.Errorf("load config: %w", err)
}
config, err := parseConfig(data)
if err != nil {
return nil, fmt.Errorf("load config: %w", err)
}
return config, nil
}func ProcessBatch(items []Item) ([]Result, error) {
results := make([]Result, 0, len(items))
for _, item := range items {
result, err := process(item)
if err != nil {
return nil, fmt.Errorf("process item %s: %w", item.ID, err)
}
results = append(results, result)
}
return results, nil
}type MultiError []error
func (m MultiError) Error() string {
var msgs []string
for _, err := range m {
msgs = append(msgs, err.Error())
}
return strings.Join(msgs, "; ")
}
func ValidateAll(users []*User) error {
var errs MultiError
for _, user := range users {
if err := Validate(user); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return errs
}
return nil
}func MustCompile(pattern string) *regexp.Regexp {
re, err := regexp.Compile(pattern)
if err != nil {
panic(err) // Invalid pattern is programmer error
}
return re
}func SafeExecute(fn func()) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic: %v", r)
}
}()
fn()
return nil
}type contextError struct {
op string
err error
}
func (e *contextError) Error() string {
return fmt.Sprintf("%s: %v", e.op, e.err)
}
func (e *contextError) Unwrap() error {
return e.err
}
func withContext(op string, err error) error {
if err == nil {
return nil
}
return &contextError{op: op, err: err}
}func handler(w http.ResponseWriter, r *http.Request) {
user, err := getUser(r.Context(), r.URL.Query().Get("id"))
if errors.Is(err, ErrNotFound) {
http.Error(w, "User not found", http.StatusNotFound)
return
}
if errors.Is(err, ErrUnauthorized) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
if err != nil {
log.Printf("get user: %v", err)
http.Error(w, "Internal error", http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(user)
}func processAsync(items []Item) error {
errCh := make(chan error, len(items))
for _, item := range items {
go func(it Item) {
errCh <- process(it)
}(item)
}
// Collect errors
for range items {
if err := <-errCh; err != nil {
return fmt.Errorf("process failed: %w", err)
}
}
return nil
}