Lesson 13 · 13 of 20
Errors as values · Go
Treat errors as values in Go: create them with errors.New and fmt.Errorf, check them with if err != nil and recognise them with errors.Is.

Go has no exceptions: a function that can fail returns an error as its last result. withdraw returns the new balance and an error; when everything goes well, the error is nil, which means "no error".
errors.New("insufficient funds") creates an error with a message. Stored in the ErrNoFunds variable, it is a sentinel error: a known value you can compare against later. fmt.Errorf builds an error with formatting, just like Printf: invalid amount -5.00.
With %w, fmt.Errorf wraps another error: the message adds detail (withdraw 90.00: insufficient funds), but the original error is still inside. errors.Is(err, ErrNoFunds) looks for it, which is why it gives true for the 90 euro withdrawal and false for the negative amount.
The caller always checks: if err != nil. If there is an error, it prints it and, with continue, moves on to the next amount without touching the balance; otherwise it keeps newBalance. So 30 and then 45 euros come out of 100, leaving 25.00.
Code · main.go
package mainimport ( "errors" "fmt")// errors.New creates an error value that can be recognised later.var ErrNoFunds = errors.New("insufficient funds")// The error goes last; nil means that everything went well.func withdraw(balance, amount float64) (float64, error) { switch { case amount <= 0: return balance, fmt.Errorf("invalid amount %.2f", amount) case amount > balance: return balance, fmt.Errorf("withdraw %.2f: %w", amount, ErrNoFunds) // %w wraps it } return balance - amount, nil}func main() { balance, amounts := 100.0, []float64{30, -5, 90, 45} for i := 0; i < len(amounts); i++ { newBalance, err := withdraw(balance, amounts[i]) if err != nil { fmt.Println("Error:", err) fmt.Println(" is ErrNoFunds?", errors.Is(err, ErrNoFunds)) continue } balance = newBalance fmt.Printf("Took %.2f, balance %.2f\n", amounts[i], balance) }}Output · go run main.go
Took 30.00, balance 70.00 Error: invalid amount -5.00 is ErrNoFunds? false Error: withdraw 90.00: insufficient funds is ErrNoFunds? true Took 45.00, balance 25.00
Key points
- The error is the last result;
nilmeans no error. errors.Newcreates an error;fmt.Errorfa formatted one.%wwraps one error inside another.errors.Isrecognises an error even when it is wrapped.- Always check with
if err != nil.
Exercise
Add a daily limit: a sentinel error ErrDailyLimit that withdraw returns, wrapped with %w, when the amount is over 60 euros, and check for it in main with errors.Is.