Tutorials Logic, IN info@tutorialslogic.com

Golang Error Handling: errors, fmt.Errorf, wrapping and panic

Golang Error Handling

Golang handles expected failures with ordinary return values. A function that can fail usually returns a useful result and an error. The caller checks whether the error is nil before using the result.

This explicit style makes failure paths visible. Instead of hidden exceptions jumping out of a function, the code shows exactly where errors are checked, wrapped, handled, logged, or returned to the caller.

Add one worked example that compares the normal path with the boundary case for Golang Error Handling: errors, fmt.Errorf, wrapping and panic.

Golang Error Handling errors fmt.Errorf wrapping and panic should be studied as a practical Golang lesson, not as a label. Start by naming the input, the rule that changes the input, and the result a learner should be able to predict after reading the page.

In the golang > error-handling page, the notes should connect the definition with a working scenario, a mistake that beginners actually make, and the exact check that proves the fix. That makes the topic useful for coding, debugging, and interview revision.

Errors Are Values

Return Result and Error

Return Result and Error
package main

import (
    "fmt"
    "strconv"
)

func parseLimit(value string) (int, error) {
    limit, err := strconv.Atoi(value)
    if err != nil {
        return 0, fmt.Errorf("parse limit %q: %w", value, err)
    }

    return limit, nil
}

func main() {
    limit, err := parseLimit("25")
    if err != nil {
        fmt.Println("error:", err)
        return
    }

    fmt.Println("limit:", limit)
}

Creating Sentinel Errors

A sentinel error is a package-level error value used for a known condition. Common examples are not found, already exists, unauthorized, or invalid state.

Sentinel errors are useful when callers need to make decisions based on a specific failure. Use errors.Is to compare them, especially after wrapping.

Known Error Values

Known Error Values
package tutorials

import (
    "errors"
    "fmt"
)

var ErrNotFound = errors.New("tutorial not found")

func LoadTutorial(slug string) error {
    return fmt.Errorf("load tutorial %q: %w", slug, ErrNotFound)
}

func HandleTutorial(slug string) {
    err := LoadTutorial(slug)
    if errors.Is(err, ErrNotFound) {
        fmt.Println("show 404 page")
        return
    }
}

Adding Context with Wrapping

Use fmt.Errorf with %w to add context while preserving the original error. Context should explain what operation failed and include important values, such as an ID, filename, route, or user action.

Wrapping lets logs tell a story from high-level operation to low-level cause. The caller can still use errors.Is for known sentinel errors and errors.As for custom error types.

Tool Purpose
fmt.Errorf("...: %w", err) Add context while preserving the original error.
errors.Is(err, target) Check whether an error matches a known error value.
errors.As(err, &target) Extract a custom error type from an error chain.

Wrap at Boundaries

Wrap at Boundaries
func SaveProfile(userID int, input ProfileInput) error {
    if err := validateProfile(input); err != nil {
        return fmt.Errorf("validate profile for user %d: %w", userID, err)
    }

    if err := repository.Save(userID, input); err != nil {
        return fmt.Errorf("save profile for user %d: %w", userID, err)
    }

    return nil
}

Custom Error Types

A custom error type is useful when callers need structured details, not just a message. For example, a validation error may include the field name, a code, and a user-friendly message.

A type becomes an error when it implements the Error() string method. Keep the method message helpful for logs, and expose fields when code needs to make decisions.

Structured Validation Error

Structured Validation Error
type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return e.Field + ": " + e.Message
}

func validateTitle(title string) error {
    if title == "" {
        return ValidationError{Field: "title", Message: "is required"}
    }
    return nil
}

func handle() {
    err := validateTitle("")
    var validationErr ValidationError
    if errors.As(err, &validationErr) {
        fmt.Println(validationErr.Field, validationErr.Message)
    }
}

Designing Error Messages

Good error messages explain the failed operation and important values. Keep messages lowercase and avoid punctuation unless the message contains multiple sentences. This convention helps wrapped errors read naturally.

Return errors at the right level. Low-level functions should describe the technical operation that failed. Higher-level functions can wrap with business context so the final error is useful in logs and debugging.

  • Prefer open config file: permission denied over Error!.
  • Include meaningful values such as IDs, slugs, paths, and operation names.
  • Do not match errors by string content for program decisions.
  • Avoid logging the same error at every layer; log at a boundary where action can be taken.

panic and recover

Use panic for programmer mistakes and impossible states, not for normal validation failures. A missing title in an API request should return an error response, not panic.

Some servers recover from panics at a boundary so they can log the issue and keep serving other requests. Even then, ordinary failures should still use error. Recovery is a safety net, not the main error-handling strategy.

Situation Use
Invalid user input Return an error or HTTP 400 response.
Missing database record Return a not-found error.
Impossible internal state Panic may be acceptable.
Server boundary Recover, log, and return a safe response.

Golang Error Handling errors fmt.Errorf wrapping and panic in Real Work

Golang Error Handling errors fmt.Errorf wrapping and panic matters in Golang because it changes how a program is written, tested, or debugged. The page should explain the normal flow first: what the developer writes, what the runtime or platform does, and what result should appear.

When teaching Golang Error Handling errors fmt.Errorf wrapping and panic, avoid stopping at syntax. Show the surrounding decision: why this feature is chosen, what problem it removes, and what would become harder if the feature were not used.

  • Identify the concrete problem solved by Golang Error Handling errors fmt.Errorf wrapping and panic.
  • Show the normal input, operation, and output for golang.
  • Mention the nearby alternative a beginner may confuse with this topic.
  • Tie the explanation to a real project task, command, component, query, or debugging step.

Golang Error Handling errors fmt.Errorf wrapping and panic normal path trace

Golang Error Handling errors fmt.Errorf wrapping and panic normal path trace
1. Define the input for Golang Error Handling errors fmt.Errorf wrapping and panic.
2. Apply the rule from the lesson.
3. Compare the actual result with the expected result.
4. Record the fix if the result differs.

Golang Error Handling errors fmt.Errorf wrapping and panic edge path trace

Golang Error Handling errors fmt.Errorf wrapping and panic edge path trace
1. Try empty, missing, duplicate, or invalid data.
2. Identify where Golang Error Handling errors fmt.Errorf wrapping and panic changes behavior.
3. Explain the safest correction.
4. Retest the normal path.
Key Takeaways
  • Expected failures should be returned as error.
  • Return zero values with errors and check err != nil before using results.
  • Wrap errors with %w to preserve causes while adding context.
  • Use errors.Is and errors.As instead of string matching.
  • Custom error types are useful when callers need structured details.
  • Do not use panic for normal validation or business failures.
Common Mistakes to Avoid
WRONG Memorizing Golang Error Handling errors fmt.Errorf wrapping and panic without the situation where it is useful.
RIGHT Connect Golang Error Handling errors fmt.Errorf wrapping and panic to a concrete Golang task.
Purpose makes syntax easier to recall.
WRONG Testing Golang Error Handling errors fmt.Errorf wrapping and panic only with the perfect input.
RIGHT Include empty, missing, duplicate, incompatible, or failed cases when relevant.
Real bugs usually appear outside the perfect path.
WRONG Changing code before reading the visible symptom or error message.
RIGHT Inspect the output, state, configuration, or stack trace connected to Golang Error Handling errors fmt.Errorf wrapping and panic.
Evidence keeps debugging focused.
WRONG Memorizing Golang Error Handling errors fmt.Errorf wrapping and panic without the situation where it is useful.
RIGHT Connect Golang Error Handling errors fmt.Errorf wrapping and panic to a concrete Golang task.
Purpose makes syntax easier to recall.

Practice Tasks

  • Modify the example so it handles a different input or condition.
  • Write one mistake related to Golang Error Handling: errors, fmt.Errorf, wrapping and panic, then fix it and explain the fix.
  • Summarize when to use Golang Error Handling: errors, fmt.Errorf, wrapping and panic and when another approach is better.
  • Write a small example that uses Golang Error Handling errors fmt.Errorf wrapping and panic in a realistic Golang scenario.
  • Change one important value in the Golang Error Handling errors fmt.Errorf wrapping and panic example and predict the result first.

Frequently Asked Questions

The common mistake is memorizing syntax without understanding when the behavior changes or fails.

Remember the problem it solves in Golang, then attach the syntax or steps to that problem.

You can predict the result of a small example, explain a failure case, and choose it over a nearby alternative for a clear reason.

They often copy the syntax but skip the state, input, dependency, selector, route, type, or configuration that controls the behavior.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.