Video Coming Soon...

Created by Zed A. Shaw Updated 2025-10-07 14:32:54

13: Error Handling

WARNING This exercise is in DRAFT status, so there may be errors. If you find any, please email me at help@learncodethehardway.com so I can fix them.

Go's error handling mostly involves dealing with a special return value from functions. There's another style called "panic/recover" but it's so bad I don't think I'll bother teaching it to you until it's needed later for some reason. In the normal Go error handling you do this:

  1. Call function.
  2. Get 2 return values a result and an error.
  3. Create a defer for the first if needed.
  4. Handle the error however is necessary.

Functions Can Have Multiple Returns

For this to work you need to learn that functions can return more than one value. Here's the classic example of this feature:

func swap(a int, b int) (int, int) {
    return b, a
}

func main() {
    x := 1
    y := 2
    x, y = swap(x, y)
}

In this example I have a function swap that takes two int named a and b, but the return is return b, a. This will swap them around so you can reassign their values to do the swap. Study this for a bit before continuing on.

Returning a Value and Error

With that we can then make a function that returns a value and an error:

func MustOpen(filename string) (os.File, error) {
    the_file, err := os.Open(filename)
    return the_file, err
}

When you call MustOpen it will call the os.Open() function, which return a file and a possible error. We don't do anything with this and simply return both again, but we can handle it instead.

Detecting and Handling Errors

To handle an error you check if it is equal to nil. The nil value represents "not set" or "nothing." If there IS an error then the err will be set to something that you have to handle. If this IS NOT an error then it will be set to nil and you can ignore it. Let's handle the os.Open() error:

func MustOpen(filename string)  os.File {
    the_file, err := os.Open(filename)
    if err != nil { log.Fatal("failed to open")
    return the_file
}

It's common for functions starting with Must to cause the program to exit if there's any failure. Typically you want this in programs that run once to do something, but not in servers. From the defer exercise you know that log.Fatal causes programs to exit immediately, so this code will now exit the program if there are any errors opening the file.

NOTE I'm skipping over what os.File is until a later exercise in the second module. Just know that's what a file is in Go.

The Code

Now we can look at this code:

View Source file ex13/main.go Only

package main

import (
    "fmt"
)

func ReadName() string {
    fmt.Print("What's your name? ")

    var name string
    _, err := fmt.Scan(&name)
    if err != nil { panic("WRONG!") }

    return name
}

func main() {
    name := ReadName()
    fmt.Println("Thank you for your service citizen", name)
}

The Breakdown

I'll explain every line just like normal, but obiously I'll skip things you should already know like } ends a block.

The Practice

  1. Break It -- Try causing and handling different errors, getting return values wrong, and anything else that messes with error handling.
  2. Change It -- You've seen fmt.Scan so can you do more with that? Can you combine it with if or switch? Can you repeatedly ask for a name until you get a valid one?
  3. Remake It -- As usual, write a description the recreate it from memory using the description. The more you do this, the better you'll get.

Study Drills

  1. Write a few different functions that handle or return errors in different ways.
  2. Find the documentation for the log function on Go's website and try to use it.
  3. Is it better to use log.Fatal or to do your own error and exit handling? Why?
Previous Lesson Next Lesson

Register for Learn Go the Hard Way

Register today for the course and get the all currently available videos and lessons, plus all future modules for no extra charge.