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.
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)
}
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.
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
}
}
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. |
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
}
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.
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)
}
}
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.
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 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.
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.
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.
Memorizing Golang Error Handling errors fmt.Errorf wrapping and panic without the situation where it is useful.
Connect Golang Error Handling errors fmt.Errorf wrapping and panic to a concrete Golang task.
Testing Golang Error Handling errors fmt.Errorf wrapping and panic only with the perfect input.
Include empty, missing, duplicate, incompatible, or failed cases when relevant.
Changing code before reading the visible symptom or error message.
Inspect the output, state, configuration, or stack trace connected to Golang Error Handling errors fmt.Errorf wrapping and panic.
Memorizing Golang Error Handling errors fmt.Errorf wrapping and panic without the situation where it is useful.
Connect Golang Error Handling errors fmt.Errorf wrapping and panic to a concrete Golang task.
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.
Explore 500+ free tutorials across 20+ languages and frameworks.