SyntaxStudy
Sign Up
Go Error Handling Fundamentals
Go Beginner 1 min read

Error Handling Fundamentals

In Go, errors are values. The built-in `error` interface has a single method: `Error() string`. Functions signal failure by returning an error as their last return value alongside their result. Callers are expected to check the error immediately after the call. This explicit, in-band error handling makes error paths visible in the code and impossible to ignore silently. The `errors.New` function creates a simple error value from a string. The `fmt.Errorf` function creates a formatted error message and, when used with the `%w` verb, wraps an existing error so the original error can be unwrapped later. Wrapping errors is the standard way to add context (file name, operation, parameters) as the error propagates up the call stack. When checking errors, the idiomatic pattern is `if err != nil { return err }`. It is considered bad practice to use `panic` for expected errors such as invalid input or network failures. Panics are reserved for programming errors and truly unrecoverable situations. The explicit error return style, while verbose, produces code where every failure path is deliberate and traceable.
Example
package main

import (
    "errors"
    "fmt"
    "strconv"
)

// Custom error type
type ParseError struct {
    Input string
    Err   error
}

func (e *ParseError) Error() string {
    return fmt.Sprintf("ParseError: cannot parse %q: %v", e.Input, e.Err)
}

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

func parsePositive(s string) (int, error) {
    n, err := strconv.Atoi(s)
    if err != nil {
        return 0, &ParseError{Input: s, Err: err}
    }
    if n <= 0 {
        return 0, fmt.Errorf("parsePositive: %d is not positive", n)
    }
    return n, nil
}

func main() {
    inputs := []string{"42", "-5", "abc", "100"}

    for _, s := range inputs {
        n, err := parsePositive(s)
        if err != nil {
            // Type assertion
            var pe *ParseError
            if errors.As(err, &pe) {
                fmt.Printf("type error for %q: %v\n", pe.Input, pe.Err)
            } else {
                fmt.Printf("value error: %v\n", err)
            }
            continue
        }
        fmt.Printf("parsed: %d\n", n)
    }
}