Skip to content
Theory · Errors · lesson 4 of 11

Checking if err != nil

The delivery note from the previous lessons is read right away, while the box is still closed. Let's see why errors are treated the same way. The strconv.Atoi function turns a string into an int and returns an (int, error) pair. It rejects a string that is not an integer as a whole, even if the string starts with digits:

GO
package main

import (
    "fmt"
    "strconv"
)

func main() {
    n, err := strconv.Atoi("42")
    fmt.Println(n, err) // 42 <nil>
    n, err = strconv.Atoi("7 days")
    fmt.Println(n, err) // 0 strconv.Atoi: parsing "7 days": invalid syntax
}

Let's walk through the example line by line:

  1. strconv.Atoi("42") parses the string, and the program prints 42 <nil>.
  2. For "7 days" the function returns 0 together with the error, not the digit 7 it read.
  3. The second Println prints 0 and the error text. The text names the function and the string it failed to parse.

But 0 can also be a real result: strconv.Atoi("0") gives 0 as well. The number cannot tell success from failure—only err does. A closed box does not show that something is wrong with it, but the note does.

Check right after the call

That is why the error is checked on the very next line after the call: if err != nil. If there is an error, the function returns it to the caller at once, and only the successful path continues:

GO
func total(a, b string) (int, error) {
    x, err := strconv.Atoi(a)
    if err != nil {
        return 0, err
    }
    y, err := strconv.Atoi(b)
    if err != nil {
        return 0, err
    }
    return x + y, nil
}

The total function parses two strings and adds the numbers. Let's go through it step by step:

  1. x, err := strconv.Atoi(a) parses the first string.
  2. The check if err != nil returns 0 and the error itself on failure, and the rest of the code does not run.
  3. y, err := strconv.Atoi(b) parses the second string. Here := is allowed because there is a new variable y on the left. The variable err is not created again; it gets a new value.
  4. The second check works like the first.
  5. return x + y, nil runs only if both strings were parsed.

Early return

Leaving the function at once on an error is called an early return. A parcel with a bad note goes back at once, unopened. This technique has two benefits:

  • each check is short and sits right after its call;
  • the main code stays free of extra indentation: the addition stands at the end, on the first level.

Who decides what to do

The total function does not print the error itself; it returns it upward. The code that knows what to do decides:

  • show a message;
  • ask for the input again;
  • end the program.

The calling code checks the error the same way:

GO
sum, err := total("12", "x")
if err != nil {
    fmt.Println("total:", err)
    return
}
fmt.Println(sum)

Let's see what happens:

  1. total("12", "x") returns an error: the string "x" cannot be parsed.
  2. The check finds the error, and the program prints total: strconv.Atoi: parsing "x": invalid syntax.
  3. return ends the work, and the program never reaches fmt.Println(sum).

While err is not nil, the value sum is not used: it holds a zero value, not a result.

Here the courier picture parts ways with Go. A courier won't leave until you sign the note. The Go compiler demands only one thing: a declared variable err has to be read somewhere.

Common mistake

The compiler rejects an err variable that is never read: declared and not used: err. So it is sometimes replaced with _, and the number is taken as is:

GO
n, _ := strconv.Atoi("ten") // ✗
fmt.Println(n * 2)          // 0

The program compiles and prints 0, though the string is not a number at all. The note was thrown away unread, and bad input silently turned into zero and went on into the calculations. Keep the error in err and check it before you use n.

Key points

  • Check the error on the next line after the call: if err != nil.
  • On an error, the function returns it upward at once—that is an early return.
  • While err != nil, the other results are not used: on an error strconv.Atoi returns 0.
  • Don't throw an error away with _: bad input silently turns into a zero value.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way