Fix Rust Error E0499: cannot borrow as mutable more than once at a time

intermediate๐Ÿฆ€ Rust2026-03-20| Rust 1.x (any version), rustc compiler, Linux / macOS / Windows

Error Message

error[E0499]: cannot borrow `vec` as mutable more than once at a time
#rust#borrow-checker#mutable-reference#ownership

The Error

Two mutable references to the same variable, both alive at once. The Rust compiler sees it immediately and refuses to build:

error[E0499]: cannot borrow `vec` as mutable more than once at a time
 --> src/main.rs:5:18
  |
4 |     let first = &mut vec;
  |                 -------- first mutable borrow occurs here
5 |     let second = &mut vec;
  |                  ^^^^^^^^ second mutable borrow occurs here
6 |     println!("{}", first[0]);
  |                    ----- first borrow later used here

This is the borrow checker doing its job. The rule is strict: one mutable reference at a time, no exceptions.

Why This Happens

Rust prevents data races at compile time. Two simultaneous mutable references to the same data means one could modify or invalidate it while the other is reading โ€” a classic bug in C/C++ that Rust makes structurally impossible.

The tricky part: "at the same time" doesn't mean what you'd expect. A mutable borrow stays alive until its last use, not until you assign the next variable. This trips up a lot of developers coming from other languages.

Step-by-Step Fix

Step 1: Identify the overlapping borrows

Run rustc --explain E0499 to get the compiler's full explanation. The error output also shows you exactly where each borrow starts and where it's still in use. Your goal: make sure the first mutable borrow is completely done before the second one starts.

Step 2: Let the first borrow go out of scope

The simplest fix โ€” use the first reference completely, then create the second.

fn main() {
    let mut vec = vec![1, 2, 3];

    // BAD: both borrows alive at the same time
    // let first = &mut vec;
    // let second = &mut vec; // error!

    // GOOD: first borrow is done before second begins
    {
        let first = &mut vec;
        first.push(4);
    } // first borrow ends here

    let second = &mut vec;
    second.push(5);

    println!("{:?}", vec); // [1, 2, 3, 4, 5]
}

Step 3: Use indices instead of multiple references (for collections)

Trying to mutably reference two elements of the same Vec at once is one of the most frequent triggers for E0499. Index-based access sidesteps the problem entirely:

fn main() {
    let mut data = vec![10, 20, 30];

    // BAD: two mutable references into the same Vec
    // let a = &mut data[0];
    // let b = &mut data[1]; // error!

    // GOOD: use indices directly
    data[0] += data[1]; // reads [1] and writes [0] in one statement
    println!("{:?}", data); // [30, 20, 30]

    // Or: split the slice
    let (left, right) = data.split_at_mut(1);
    left[0] = right[0] + right[1];
    println!("{:?}", data); // [50, 20, 30]
}

Step 4: Use split_at_mut for disjoint slice mutation

Need two mutable views into different parts of the same collection? split_at_mut divides a slice into two non-overlapping mutable halves. The borrow checker accepts this because the two halves provably can't alias:

fn swap_first_last(data: &mut Vec<i32>) {
    let len = data.len();
    if len < 2 {
        return;
    }
    let (head, tail) = data.split_at_mut(len - 1);
    std::mem::swap(&mut head[0], &mut tail[0]);
}

fn main() {
    let mut v = vec![1, 2, 3, 4, 5];
    swap_first_last(&mut v);
    println!("{:?}", v); // [5, 2, 3, 4, 1]
}

Step 5: Restructure logic into separate passes

Sometimes the design itself is the problem. Reading from and writing to the same structure simultaneously is inherently conflicting โ€” break it into two distinct passes instead:

fn main() {
    let mut scores: Vec<i32> = vec![3, 7, 2, 9, 1];

    // BAD pattern: trying to find max and update in one pass
    // with multiple mutable borrows

    // GOOD: two separate passes
    let max = *scores.iter().max().unwrap(); // read pass (immutable borrow)
    for s in scores.iter_mut() {            // write pass (mutable borrow)
        *s = if *s == max { 100 } else { *s };
    }

    println!("{:?}", scores); // [3, 7, 2, 100, 1]
}

Step 6: Use RefCell for interior mutability (when needed)

Sometimes the borrow checker is too conservative โ€” graph-like structures and certain recursive patterns are common examples. RefCell<T> is the escape hatch: it defers the borrow check to runtime instead of compile time.

use std::cell::RefCell;

fn main() {
    let data = RefCell::new(vec![1, 2, 3]);

    {
        let mut borrow = data.borrow_mut();
        borrow.push(4);
    } // mutable borrow released here

    println!("{:?}", data.borrow()); // [1, 2, 3, 4]
}

Warning: RefCell panics at runtime if you actually violate the borrow rules. Treat it as a last resort โ€” restructuring the code is almost always the cleaner solution.

Verify the Fix

Build the project and confirm E0499 is gone:

cargo build

Then run your tests to make sure nothing broke:

cargo test

Also worth running cargo clippy โ€” it catches patterns that tend to cause this error before you even hit the compiler:

cargo clippy

Quick Reference: Which Fix to Use

  • Borrows don't actually overlap? Add a block { } to scope the first borrow.
  • Two elements of a Vec? Use split_at_mut() or index arithmetic.
  • Read then write pattern? Separate into two passes.
  • Complex shared state? Use RefCell<T> (single-threaded) or Mutex<T> (multi-threaded).
  • Graph / tree structures? Consider arena crates like slotmap or generational-arena.

Common Mistakes

  • Assuming the borrow ends at the assignment line. It doesn't. A borrow lives until its last use. NLL (Non-Lexical Lifetimes), introduced in Rust 2018, handles many obvious cases automatically โ€” but complex patterns still catch people off guard.
  • Reaching for RefCell first. It's a last resort, not a convenience. Restructuring the code is almost always the right call.
  • Calling a &mut self method while holding a reference to a field. That method call borrows the entire struct mutably. Any existing reference to any field of that struct will conflict โ€” even if the method never touches that particular field.

Related Error Notes