Skip to main content
eLearner.app
Module 2 · Lesson 5 of 510/50 in the course~12 min
Module lessons (5/5)

Errors: the `if err != nil` pattern

In Go, errors are values, not exceptions. A function that can fail returns the error as the last value, and the caller checks it explicitly. It is explicit, predictable, easy to test — the price is a bit more verbosity.

The error interface

error is a small interface built into the language:

Go
type error interface {
    Error() string
}

Any type that implements Error() string is an error.

The fundamental pattern

Go
v, err := operazione()
if err != nil {
    // gestisci o propaga
    return err
}
// usa v

You will see this thousands of times: it is the idiomatic code for every fallible call. Do not feel guilty about the repetition — it is a feature, not a bug.

Building errors: errors.New and fmt.Errorf

Go
import (
    "errors"
    "fmt"
)

err1 := errors.New("file mancante")
err2 := fmt.Errorf("apertura %q fallita: permesso negato", path)

fmt.Errorf is perfect when you want to include variables in the message.

Wrapping with %w

To propagate an error adding context WITHOUT losing the original:

Go
f, err := os.Open(path)
if err != nil {
    return fmt.Errorf("config: %w", err)
}

%w "wraps" the original error, recoverable later with errors.Is (equality for sentinels) or errors.As (for concrete type):

Go
if errors.Is(err, os.ErrNotExist) {
    // file inesistente, gestione speciale
}

Sentinel errors

These are errors exported as variables, used for comparisons with errors.Is:

Go
var ErrNotFound = errors.New("non trovato")

func find(id int) (Item, error) {
    // ...
    return Item{}, ErrNotFound
}

// chiamante:
if errors.Is(err, ErrNotFound) { ... }

panic and recover (preview)

panic exists in Go but is reserved for unrecoverable errors (e.g. bugs, violated invariants), not for normal control flow. We will go deeper in the Functions module with defer/recover. For now: do not use it in place of the if err != nil pattern.

Try it

Exercise#go.m2.l5.e1
Attempts: 0Loading…

Handle the error from strconv.Atoi: if err != nil, print it and return; otherwise print n.

Loading editor…
Show hint

The canonical pattern: check `err != nil`, log/return, then use `n`.

Solution available after 3 attempts

Exercise#go.m2.l5.e2
Attempts: 0Loading…

Implement safeDiv: if b == 0 return 0 and an errors.New('divisione per zero'); otherwise a/b and nil.

Loading editor…
Show hint

Check `b == 0` BEFORE the division to avoid the run-time panic.

Solution available after 3 attempts

Quiz#go.m2.l5.e3
Ready

Which is the idiomatic pattern to handle an error in Go?

Go
v, err := f()
// poi?
Answer options

Recap

  • error is an interface with one method Error() string.
  • Canonical pattern: v, err := f(); if err != nil { return err }.
  • Build errors with errors.New(msg) or fmt.Errorf("ctx: %w", err).
  • Use %w for wrapping and errors.Is / errors.As to inspect the chain.
  • panic only for unrecoverable errors, NOT for normal control flow.