The Go runtime is panicking because a program is trying to access an element in a slice or array using an index that doesn’t exist within its valid bounds. This is a fundamental error in how the program is managing its data structures, leading to an immediate halt.
Common Causes and Fixes
1. Off-by-One Error in Loop Iteration
- Diagnosis: Examine
forloops that iterate over slices or arrays. Look for conditions likei <= len(slice)ori < len(slice) + 1. - Cause: The loop condition allows the index
ito reach a value equal to the length of the slice (or array), which is one position beyond the last valid index (which islen(slice) - 1). - Fix: Change the loop condition to
i < len(slice).
This ensures the index// Incorrect for i := 0; i <= len(mySlice); i++ { fmt.Println(mySlice[i]) // Panics when i == len(mySlice) } // Correct for i := 0; i < len(mySlice); i++ { fmt.Println(mySlice[i]) }inever exceedslen(mySlice) - 1.
2. Incorrect Index Calculation with External Input
- Diagnosis: If the index is derived from user input, network data, or configuration files, print the calculated index value just before the access.
- Cause: External data might be malformed, providing an index that’s too large or negative. For instance, a user might submit
100for an index in a slice of length50. - Fix: Add validation checks for the index before using it.
This prevents out-of-bounds access by ensuring the index is within theuserInputIndex := getUserInput() // Assume this returns an int if userInputIndex < 0 || userInputIndex >= len(mySlice) { fmt.Println("Error: Invalid index provided.") // Handle error appropriately, e.g., return an error, skip operation } else { fmt.Println(mySlice[userInputIndex]) }[0, len(mySlice)-1]range.
3. Accessing an Empty Slice or Array
- Diagnosis: Check if the slice or array being accessed has a length of zero.
- Cause: The program attempts to access
slice[0]orarray[0]when the slice/array is empty (len(slice) == 0). An empty slice has no valid indices. - Fix: Add a check for the length of the slice/array before attempting access.
This guards against accessing any index on a zero-length collection.// Incorrect if mySlice != nil { // This check isn't enough if mySlice is just empty fmt.Println(mySlice[0]) // Panics if len(mySlice) == 0 } // Correct if len(mySlice) > 0 { fmt.Println(mySlice[0]) } else { fmt.Println("Slice is empty, cannot access element.") }
4. Incorrectly Sized Slices After Appending
- Diagnosis: If the slice is modified using
append, verify the size of the slice after the append operation and before subsequent access. - Cause: A common mistake is assuming a slice has grown to a certain size after an append, but the append operation itself might have failed to grow it as expected (e.g., due to capacity issues in complex scenarios, though less common for simple appends) or the logic using the appended element is flawed. More often, the index used to access the newly appended element is calculated incorrectly (e.g., using the length before appending).
- Fix: Use the length of the slice after the append operation to index the new element, or more reliably, use
slice[len(slice)-1].
This correctly targets the last element, which is the one most recently added.mySlice = append(mySlice, newValue) // Incorrect: Assuming the new element is at index len(mySlice) if len(mySlice) was used before append // fmt.Println(mySlice[len(mySlice)]) // This would panic // Correct way to access the newly appended element fmt.Println(mySlice[len(mySlice)-1])
5. Nil Slice vs. Empty Slice Confusion
- Diagnosis: Differentiate between a
nilslice and an empty slice ([]T{}). - Cause: A
nilslice has a length and capacity of 0. Accessing an index on anilslice will panic, just like an empty slice. Sometimes, code might checkif mySlice == nilbut then proceed to accessmySlice[0]without checkinglen(mySlice). - Fix: Always check
len(slice)to determine if a slice is safe to access, regardless of whether it’snilor an explicitly initialized empty slice.
Thevar nilSlice []int // nilSlice has len 0, cap 0 emptySlice := []int{} // emptySlice has len 0, cap 0 // Incorrectly assuming nil check is sufficient if nilSlice == nil { // fmt.Println(nilSlice[0]) // This will panic } // Correct check for both nil and empty slices if len(nilSlice) > 0 { fmt.Println(nilSlice[0]) } else { fmt.Println("Slice is nil or empty.") }len()function correctly reports 0 for bothniland empty slices, making it the universal check for index safety.
6. Incorrect Index for Map Values (Less Common but Possible)
- Diagnosis: If you are iterating over a map and using the map’s values to index into a slice or array, check the map’s value.
- Cause: The value retrieved from the map might be an invalid index for the target slice/array. This can happen if the map data isn’t validated against the slice dimensions.
- Fix: Validate the map value before using it as an index.
This ensures that values from potentially untrusted sources (like maps) are safely used as indices.dataMap := map[string]int{"item1": 5} mySlice := []int{10, 20, 30} index, ok := dataMap["item1"] if ok { if index < 0 || index >= len(mySlice) { fmt.Println("Error: Map value is an invalid index.") } else { fmt.Println(mySlice[index]) } }
After fixing these, the next error you’ll likely encounter is runtime error: invalid memory address or nil pointer dereference, as programs often have interdependencies where one fix reveals another underlying issue.