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.
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.goInterpretation
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