← Debugging Guides

阅读中文版本

Go — panic: index out of range on a slice or array

Fix index out of range panics by validating bounds before access and handling slice length explicitly.

beginnerdebugginggoruntime

Symptoms

  • panic: runtime error: index out of range [3] with length 2
  • The panic occurs only for short inputs
  • Slice reslicing past the length panics
  • Concurrent append and read see an inconsistent length

Possible causes

  • An index is used without checking length
  • A slice was resliced beyond its length
  • An empty input path was not handled
  • Another goroutine mutated the slice during access

Diagnosis steps

Read the index and length from the panic

go run main.go 2>&1 | grep "index out of range"

Interpretation

The message gives the attempted index and the actual length, immediately showing the off-by-one or empty case.

Guard before access

if i < len(items) { use(items[i]) }

Interpretation

A bounds check before access prevents the panic and forces handling the out-of-range case.

Validate slice arithmetic

grep -n "\[.*:.*\]" main.go

Interpretation

Reslicing with end beyond len panics; clamping end to len avoids it.

Root cause

The code accessed an index outside the valid range for the slice or array, either from missing bounds checks, incorrect reslicing, or an empty input that was not handled.

Fix

Check length before indexing, clamp reslice bounds to the slice length, and handle empty inputs explicitly instead of assuming at least one element exists.

Verify the fix

Rerun with the input that panicked and with empty and single-element inputs, confirming the code returns a defined result instead of panicking.

Symptom walkthrough

The program panics with runtime error: index out of range, and the message gives the attempted index and the actual length, for example index 3 with length 2. This is an off-by-one, an empty input, or a reslice beyond the length. Because Go checks bounds at runtime rather than returning an error, the panic is the signal that a length assumption was wrong.

Fix in practice

Check length before indexing and define behavior for the empty case rather than assuming an element exists. Clamp reslice bounds to the length, and keep slice mutation and access ordered so another goroutine cannot change the length mid-access. A bounds check at the access point is cheap next to a crash.

Verification

Rerun with the failing input and also with empty and single-element inputs, confirming each returns a defined result. Handling the boundary cases confirms the fix rather than special-casing one input.

Diagnostic commands

Check the behavior with commands like these:

go run main.go 2>&1 | grep "index out of range"
if i < len(items) { use(items[i]) }
grep -n "\[.*:.*\]" main.go