Fix Rust Panic: index out of bounds โ€” the len is 3 but the index is 5

beginner๐Ÿฆ€ Rust2026-03-25| Rust 1.60+, all platforms (Linux, macOS, Windows)

Error Message

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 5'
#rust#panic#vec#slice#index-out-of-bounds

TL;DR

Your code is accessing a Vec or slice at an index that doesn't exist. The fastest safe fix is swapping vec[i] for vec.get(i), which returns an Option instead of blowing up.

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 5'
// This panics whenever i >= vec.len()
let val = vec[i];

// This never panics โ€” handle the None case yourself
if let Some(val) = vec.get(i) {
    println!("Got: {}", val);
} else {
    eprintln!("Index {} out of bounds (len = {})", i, vec.len());
}

Root Cause

Rust's [] operator on Vec and slices is strict by design. Out-of-range access? The runtime panics. No undefined behavior, no silent memory corruption like in C โ€” just an immediate, loud crash.

A few situations that reliably trigger this:

  • Hard-coded index that worked in dev but breaks on real data (classic)
  • Off-by-one in a loop โ€” 0..vec.len() is fine, 0..=vec.len() goes one past the end
  • Computing an index from user input or config without validating it first
  • Slicing a Vec after filtering or truncating it, but forgetting to update the old index
  • Multi-threaded code where another thread shrinks the Vec between your index calculation and your access

The panic message is actually pretty helpful here:

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 5'

len is 3 means valid indices are 0, 1, 2. You tried 5. Two slots past the end.

Fix Approaches

Option 1: Use .get() for safe access

Nine times out of ten, this is what you want in production. .get(i) returns Option<&T> โ€” Some(&val) when in bounds, None when not. No panic, ever.

fn print_element(data: &[i32], index: usize) {
    match data.get(index) {
        Some(val) => println!("data[{}] = {}", index, val),
        None => eprintln!("ERROR: index {} out of bounds (len = {})", index, data.len()),
    }
}

This compiles on any Vec<T> or &[T] slice โ€” no changes needed depending on which you're using.

Option 2: Explicit bounds check before indexing

Sometimes you genuinely need [] โ€” mutable access, clarity, whatever. Just guard it:

let data = vec![10, 20, 30];
let i = 5;

if i  Result {
    data.get(index)
        .copied()
        .ok_or_else(|| format!("index {} out of bounds (len = {})", index, data.len()))
}

fn main() {
    let data = vec![1, 2, 3];
    match get_element(&data, 5) {
        Ok(val) => println!("Got {}", val),
        Err(e) => eprintln!("Error: {}", e),
    }
}

Finding where the panic comes from

Before you can fix it, you need to find it. Set RUST_BACKTRACE=1 and rerun:

RUST_BACKTRACE=1 cargo run

For even more detail โ€” including inlined frames that sometimes hide the real culprit:

RUST_BACKTRACE=full cargo run

Scan the backtrace for your own crate name. Skip the std:: and core:: frames at the top โ€” those are Rust internals. Your bug is in the frames below them.

Slice ranges panic too

Worth knowing: index out of bounds also fires when slicing with an out-of-range end:

let v = vec![1, 2, 3];
let slice = &v[1..10]; // panics โ€” 10 > len (3)

// Clamp the end to a valid range first
let end = 10.min(v.len());
let slice = &v[1..end]; // safe

Verification

Run it again after your fix โ€” no panic output means you got it:

# Clean run
cargo run

# Full test suite
cargo test

Add a regression test so this doesn't sneak back in:

#[test]
fn test_out_of_bounds_handled() {
    let data = vec![1, 2, 3];
    assert!(data.get(5).is_none());      // out of bounds โ†’ None, not panic
    assert_eq!(data.get(2), Some(&3));   // last valid index โ†’ Some
}

For deep validation โ€” especially in unsafe code โ€” Miri can catch memory issues that tests miss:

cargo +nightly miri test

Further Reading

  • Rust Reference โ€” SliceIndex trait and panicking behavior
  • Vec::get and slice::get in the standard library docs
  • The Rustonomicon โ€” memory safety guarantees and why Rust panics instead of UB
  • RUST_BACKTRACE environment variable documentation

Related Error Notes