← Debugging Guides

阅读中文版本

Rust E0505 — Cannot Move Out of Value While Borrowed

Fix Rust error E0505 by ending the borrow before moving, reordering operations, or cloning when the borrow must outlive the value.

beginnerdebuggingrustborrow-checkere0505

Symptoms

  • error[E0505]: cannot move out of `x` because it is borrowed
  • The compiler points at both a borrow and a later move of the same value
  • Adding a print changes whether it compiles

Possible causes

  • A reference created earlier is still used after the value is moved
  • A method takes self by value while a field reference is alive
  • A borrow is passed somewhere that keeps it alive longer than intended (NLL).

Diagnosis steps

Read both spans in the error

cargo build 2>&1 | sed -n "/E0505/,/^$/p"

Interpretation

The error shows the borrow location and the move location; ending the borrow before the move fixes it.

Use a smaller scope for the borrow

cargo build 2>&1 | grep -n "cannot move out"

Interpretation

Wrapping the borrow in a block so it drops before the move is the minimal change.

Root cause

Rust forbids using a value after its ownership has moved while a live reference to it exists. With non-lexical lifetimes the borrow ends at its last use, so the error appears exactly when a move sits before that last use.

Fix

Reorder so the borrows finish before the move, move the value last, or clone the borrowed data if the reference must outlive the owner. Prefer returning owned data from helpers.

Risk note

Cloning to silence the borrow checker can hide accidental aliasing and cost performance; clone only when the semantics require it.

Verify the fix

cargo build succeeds and the program produces the same output; run cargo clippy to confirm no new warnings.

Symptoms

The error “Rust E0505 — Cannot Move Out of Value While Borrowed” points at a specific failure mode. This guide documents the symptoms you can observe, the commands that isolate the cause, the root cause, the fix, and the checks that prove the fix works.

Observed symptoms include:

  • error[E0505]: cannot move out of x because it is borrowed
  • The compiler points at both a borrow and a later move of the same value
  • Adding a print changes whether it compiles

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Read both spans in the error

cargo build 2>&1 | sed -n "/E0505/,/^$/p"

The error shows the borrow location and the move location; ending the borrow before the move fixes it.

Step 2: Use a smaller scope for the borrow

cargo build 2>&1 | grep -n "cannot move out"

Wrapping the borrow in a block so it drops before the move is the minimal change.

Likely contributors, in order of frequency:

  • A reference created earlier is still used after the value is moved
  • A method takes self by value while a field reference is alive
  • A borrow is passed somewhere that keeps it alive longer than intended (NLL).

Root Cause

Rust forbids using a value after its ownership has moved while a live reference to it exists. With non-lexical lifetimes the borrow ends at its last use, so the error appears exactly when a move sits before that last use.

The Fix

Reorder so the borrows finish before the move, move the value last, or clone the borrowed data if the reference must outlive the owner. Prefer returning owned data from helpers.

Watch out: Cloning to silence the borrow checker can hide accidental aliasing and cost performance; clone only when the semantics require it.

let mut data = vec![1, 2, 3];

// ❌ borrow still live when data is moved
// let first = &data[0];
// let moved = data;        // E0505
// println!("{}", first);

// ✅ read, end the borrow, then move
let first = data[0];
let moved = data;
println!("{}", first);

Verify and Prevent

cargo build succeeds and the program produces the same output; run cargo clippy to confirm no new warnings.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.