Introduction
Go does not have exceptions or a try/catch mechanism like Java, Python, or JavaScript. Instead, Go treats errors as ordinary values. Functions that can fail return an error as their last return value, and callers are expected to check it explicitly with an if statement. This makes error handling explicit, visible in function signatures, and part of the normal control flow rather than a hidden jump.
Cricket analogy: There's no dramatic 'exception' thrown mid-over in cricket scoring; instead, every ball's outcome is recorded as an explicit value on the scorecard that the scorer checks after each delivery, just as Go returns errors as ordinary values checked explicitly.
Syntax
func doSomething() (int, error) {
// ... perform work ...
if somethingWentWrong {
return 0, errors.New("something went wrong")
}
return 42, nil
}
result, err := doSomething()
if err != nil {
// handle the error
log.Println("error:", err)
return
}
// use result safely here
Explanation
The built-in error type is an interface: type error interface { Error() string }. Any type that implements an Error() string method satisfies this interface. The standard library gives two easy ways to create errors: errors.New("message") creates a simple error with a static message, and fmt.Errorf("context: %w", err) creates a formatted error that can wrap an underlying error using the %w verb, preserving the original error for later inspection. The idiomatic pattern is 'if err != nil { return err }' or handle it immediately, checked right after the call that might fail.
Cricket analogy: The error interface requiring only an Error() string method is like the minimal rule that any valid dismissal report just needs a stated reason; errors.New is a plain 'stumped' note, while fmt.Errorf with %w wraps it with match context, like noting 'stumped off a wide delivery' while preserving the original ruling.
Example
package main
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Result:", result)
}
Output
Error: division by zero
Key Takeaways
- Go has no try/catch/exceptions for normal error flow; errors are ordinary return values.
- The error interface only requires a single method: Error() string.
- errors.New creates a simple static error message.
- fmt.Errorf with %w wraps an existing error while adding context.
- Always check 'if err != nil' immediately after a call that can fail.
- Explicit error checking makes failure paths visible in the code and in function signatures.
Practice what you learned
1. How does idiomatic Go signal that a function call failed?
2. What must a type implement to satisfy the built-in error interface?
3. Which function creates a new error that wraps an existing error while adding context?
4. Which statement about Go error handling is TRUE?
5. What does errors.New("message") return?
Was this page helpful?
You May Also Like
Custom Errors and errors.Is/As in Go
Build custom error types in Go and use errors.Is and errors.As to inspect and match wrapped errors.
panic, recover and defer in Go
Understand Go's defer, panic and recover mechanisms and when they should (and should not) replace normal error handling.
Multiple Return Values in Go
Understand how Go functions return multiple values, including the idiomatic error-handling pattern.
Functions in Go
Learn how to declare, call, and use functions as first-class values in Go.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics