Courses/Go/Error Handling

    Lesson 6 • Intermediate

    Error Handling 🐹

    Master Go's explicit error handling — return errors as values, wrap them with context, and build custom error types for robust applications.

    What You'll Learn in This Lesson

    • • Go's "errors as values" philosophy
    • • Custom error types and sentinel errors
    • • Error wrapping with %w and errors.Is/As
    • • Error handling patterns (early return, wrapping chain)
    • • Best practices and the decision tree

    1️⃣ Error Basics

    Go treats errors as ordinary values returned from functions. The if err != nil pattern is the cornerstone of Go error handling — verbose, but explicit and impossible to accidentally ignore.

    Try It: Error Basics

    The error return pattern and why Go chose it

    Try it Yourself »
    JavaScript
    // Error Handling in Go — Explicit Returns
    console.log("=== Go's Error Philosophy ===");
    console.log("Go treats errors as values, not exceptions.");
    console.log("Functions return an error as the LAST return value.");
    console.log("Callers MUST check the error before using the result.");
    console.log();
    
    console.log("=== The Pattern ===");
    console.log("  result, err := doSomething()");
    console.log("  if err != nil {");
    console.log("      // handle error");
    console.log("      return err");
    console.l
    ...

    2️⃣ Custom Errors & Wrapping

    Create custom error types for rich error information. Use fmt.Errorf with %w to wrap errors with context. Check wrapped errors with errors.Is and errors.As.

    Try It: Custom Errors

    Sentinel errors, custom types, and error wrapping

    Try it Yourself »
    JavaScript
    // Custom Error Types
    console.log("=== The error Interface ===");
    console.log("  type error interface {");
    console.log("      Error() string");
    console.log("  }");
    console.log("  // Any type with an Error() method is an error!");
    console.log();
    
    console.log("=== Custom Error Type ===");
    console.log("  type ValidationError struct {");
    console.log("      Field   string");
    console.log("      Message string");
    console.log("  }");
    console.log();
    console.log("  func (e *ValidationError) Error() string
    ...

    3️⃣ Error Handling Patterns

    Early returns keep the happy path unindented. Error wrapping chains add context at each level. Error groups handle concurrent errors gracefully.

    Try It: Patterns

    Early return, wrapping chains, and error groups

    Try it Yourself »
    JavaScript
    // Error Handling Patterns
    console.log("=== Pattern 1: Early Return ===");
    console.log("  func processFile(path string) error {");
    console.log("      f, err := os.Open(path)");
    console.log("      if err != nil {");
    console.log('          return fmt.Errorf("open file: %w", err)');
    console.log("      }");
    console.log("      defer f.Close()");
    console.log();
    console.log("      data, err := io.ReadAll(f)");
    console.log("      if err != nil {");
    console.log('          return fmt.Errorf("read file: %w
    ...

    4️⃣ Best Practices

    Follow Go's error handling conventions: always check errors, add context when wrapping, log at the top level only, and use the decision tree to choose the right approach.

    Try It: Best Practices

    Do's, don'ts, and the error decision tree

    Try it Yourself »
    JavaScript
    // Error Handling Best Practices
    console.log("=== Do's and Don'ts ===");
    console.log();
    
    const dos = [
      "Always check errors — never use _ for error returns in production",
      "Add context when wrapping: fmt.Errorf('read config: %w', err)",
      "Return errors to the caller — let them decide how to handle",
      "Use sentinel errors for expected conditions (ErrNotFound)",
      "Use custom error types when callers need to inspect details",
      "Log errors at the TOP level, not at every layer",
    ];
    
    const don
    ...

    ⚠️ Common Mistakes

    ⚠️
    Double logging — Don't log an error AND return it. The caller will log it again, creating duplicate logs.
    ⚠️
    Wrapping without contextreturn fmt.Errorf("%w", err) adds nothing. Always add what operation failed.
    💡
    Pro Tip: Use errors.Is instead of == to check errors. It traverses the entire wrap chain.

    📋 Quick Reference

    PatternGo Syntax
    Create errorerrors.New("msg")
    Wrap errorfmt.Errorf("ctx: %w", err)
    Check typeerrors.Is(err, ErrNotFound)
    Extract typeerrors.As(err, &target)
    Handleif err != nil { return err }

    🎉 Lesson Complete!

    You've mastered Go's error handling! Next, we'll build HTTP servers and REST APIs with Go's standard library.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service