Start learning free

LESSON 96 OF 338 · ARRAYS I

Exceeding Slice Bounds in Go: Index Out of Range

Lesson Read the full explanation

When accessing slice data with indices, the most common problem we can run into is exceeding the slice's bounds.

Remember, the items of a slice are indexed from 0 to size - 1. Any index which is not in this range is invalid.

When you try to access an item with an invalid index, Go throws an error:

ourArray := []int{50, 40, 30}

// Valid indices: 0, 1, 2
fmt.Println(myArray[0]) // Output: 50
fmt.Println(myArray[2]) // Output: 30

// Invalid indices: 3, 30, -1
fmt.Println(myArray[3])  // raises IndexOutOfBounds error
fmt.Println(myArray[30]) // raises IndexOutOfBounds error
fmt.Println(myArray[-1]) // raises IndexOutOfBounds error

As programmers, we always want to make sure that we don't exceed one slice's bounds in our programs.


Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 1
    Ctrl + Enter to check

    GO · ARRAYS I

    Exceeding Array Bounds in Go, explained

    What goes wrong

    A slice with n elements has the valid indices 0 to n - 1. If you read or write at any other index, Go does not guess and does not return a default value. The program panics: it stops at that line and prints an error with a trace of where it happened.

    ourArray := []int{50, 40, 30}
    
    fmt.Println(ourArray[0])  // 50
    fmt.Println(ourArray[2])  // 30
    fmt.Println(ourArray[3])  // panic
    fmt.Println(ourArray[30]) // panic
    

    The first two lines print 50 and 30. The third stops the program with this message, and the fourth never runs:

    panic: runtime error: index out of range [3] with length 3
    

    The message tells you the bad index and the slice's length, which is usually all you need to find the bug. The lines that ran before the panic have already produced their output.

    Run time, not compile time

    With a slice, the length is not part of the type, and it can change while the program runs. For that reason the compiler generally cannot tell whether an index is too large, even a constant one such as ourArray[30]. The program builds fine and panics only when that line executes. This is different from arrays, where the length is fixed and a constant index that is too large is rejected at compile time.

    One check does happen early: a negative constant index, like ourArray[-1], is a compile error, because no slice can ever have that index. A negative index that comes from a variable is caught at run time, with a message such as index out of range [-1].

    The exercise

    The starting code should print the last element of ages, which is 21:

    ages := []int{14, 32, 50, 21}
    
    fmt.Println(ages[len(ages)])
    

    Instead it crashes with panic: runtime error: index out of range [4] with length 4. Read the message: the program asked for index 4, but the slice has four elements at indices 0 to 3. The expression len(ages) is the number of elements, which is one more than the last index. The fix is to subtract 1:

    ages := []int{14, 32, 50, 21}
    
    fmt.Println(ages[len(ages)-1])
    
    21
    

    Empty slices

    The fix above has a catch. With an empty slice, len(s) - 1 is -1, so reading the last element panics with index out of range [-1]. When a slice might be empty, check first:

    if len(ages) > 0 {
    	fmt.Println(ages[len(ages)-1])
    }
    

    The same applies to s[0]: an empty slice has no first element either.

    Bounds in slice expressions

    Re-slicing has bounds too. In s[:k], k must not be negative and must not exceed the slice's capacity. Removing the last element of an empty slice with s = s[:len(s)-1] panics with slice bounds out of range [:-1]. The remedy is the same check on the length. Both kinds of mistake look alike: the trace that follows the message names the line that caused it.

    Avoiding the panic

    • Use len(s) - 1 for the last index.
    • In a loop, write i < len(s), never i <= len(s).
    • Use for i, v := range s when you just want to visit every element: the indices it produces are always valid.
    • Check any computed index against 0 and len(s) before using it.

    Common mistakes

    • Off-by-one with the length. The last valid index is one less than len.
    • Forgetting that the slice changed. After removing elements, the old last index no longer exists.
    • Assuming an assignment grows the slice. s[len(s)] = x panics. Use append to add an element.
    • Looking for an exception to catch. Go reports this as a panic, not a thrown error. Fix the index rather than handling the failure.

    Key takeaways

    • Valid indices for a slice are 0 to len(s) - 1.
    • An index outside that range panics at run time and stops the program.
    • The message names the index and the length, so read it first.
    • Check len(s) before touching the first or last element of a slice that may be empty.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free