Rust: index out of bounds panic
Diagnose Rust "index out of bounds" panics from slicing and Vec indexing, and replace unchecked indexing with get or iterators.
Symptoms
- thread main panicked at index out of bounds: the len is 3 but the index is 5
- A parser or loop panics only on short input
- The panic points at v[i] or &slice[a..b]
Possible causes
- Indexing a Vec or slice past its length
- A slice range where start > end or end exceeds len
- Off-by-one in a loop that iterates to len inclusive
- Assuming a split or splitn produced more parts than it did
Diagnosis steps
Read the panic message for len and index
Interpretation
Both values identify whether the index is too high or the collection is shorter than expected.
Locate the indexing expression
Interpretation
The backtrace names the line; distinguish v[i] from a range slice.
Print the collection length before the access
Interpretation
If len is smaller than assumed, upstream parsing or filtering removed elements.
Root cause
Rust bounds-checks indexing at run time: accessing a Vec, slice, or array element outside its length panics rather than reading garbage. This is memory-safe but aborts the thread, so code that assumes a minimum size must validate input or use non-panicking accessors.
Fix
Use get(i) which returns Option, get(a..b) for safe slicing, and iterators like .iter().enumerate() instead of manual indices. Validate parsed sizes before slicing, and prefer first()/last() over split indexing. Where an index is guaranteed valid, an assertion with a clear message documents the invariant.
Verify the fix
Re-run the previously failing input under a test; no panic occurs and get returns Some for valid indices, with a test asserting None for out-of-range access.
Symptoms
The program panics with index out of bounds: the len is N but the index is M. It commonly appears on short or malformed input that a happy-path loop assumed would be long enough.
Diagnosis
Read the panic values and the offending expression:
let parts: Vec<_> = line.split(',').collect();
let name = &parts[2]; // panics when fewer than 3 fields
Add a length check to confirm the collection is shorter than assumed.
Fix
Use non-panicking accessors and iterators:
let name = parts.get(2).ok_or("missing field")?;
for (i, item) in items.iter().enumerate() {
if i > 0 { /* safe: i < len */ }
}
Validate sizes before range slicing.
Verification
Run the failing input as a test asserting parts.get(2) is None rather than panicking; the parser returns a clear error and no bounds panic occurs.
Additional Notes
Rust bounds-checks indexing deliberately, so a panic here is memory safety working as designed rather than a low-level fault. Replacing indexing with an accessor that returns an optional value moves the failure from a crash to an ordinary error the caller can handle, which is usually what parsers and protocols want. Iterators remove most manual index arithmetic entirely, and when an index is provably valid, an assertion with a clear message documents the invariant and keeps the bounds check meaningful instead of redundant.