Skip to content
Select theme

How to fix error E0382: borrow of moved value

Short answer: the value was moved somewhere else, and you are trying to use the old variable. Pass a reference (&value) instead of the value, or clone() it if you genuinely need two copies.

Compiling that with cargo build prints:

error[E0382]: borrow of moved value: `s1`
--> src/main.rs:4:20
|
2 | let s1 = String::from("hello");
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
3 | let s2 = s1;
| -- value moved here
4 | println!("{}", s1);
| ^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
3 | let s2 = s1.clone();
| ++++++++

Read it from the bottom up. The compiler tells you three things: where the value moved, why the type moves, and what to write instead.

The compiler’s own note is the whole explanation: String does not implement Copy. Types that manage heap memory transfer ownership rather than duplicating it, so s1 stops being a valid name for anything the moment s2 = s1 runs.

If you are not sure why this rule exists at all, read Why does Rust move values instead of copying them? first. The short version: two owners of one heap buffer would free it twice.

Fix 1 — borrow instead of move (prefer this)

Section titled “Fix 1 — borrow instead of move (prefer this)”

Most moves are unnecessary. The function only needed to read the value, so pass a reference:

Change the signature to &String (or better, &str) and the call site to &s1:

This costs nothing at runtime and is the fix the compiler is nudging you towards.

Fix 2 — clone, when you really need two owners

Section titled “Fix 2 — clone, when you really need two owners”

clone() allocates and copies the whole heap buffer. It is the right answer when you actually want two independent values — and the wrong answer when you are using it to silence the compiler. If you find clone() on every second line, the data flow needs rethinking, not more copying.

Fix 3 — return the value from the function

Section titled “Fix 3 — return the value from the function”

Taking ownership can be fine if you hand it back:

Fix 4 — shared ownership with Rc, if one owner is not enough

Section titled “Fix 4 — shared ownership with Rc, if one owner is not enough”

When several parts of a program genuinely need to own the same data, wrap it:

Rc counts references and only drops the value when the last one goes away. Use Arc instead if the values cross thread boundaries — and remember that this is a design decision with a runtime cost, not a workaround for a borrow error.

Situation Fix
The callee only reads the value Pass &value
The callee only mutates in place Pass &mut value
You truly need two independent copies clone()
A function takes ownership and you want it back Return the value
Multiple long-lived owners are genuinely required Rc / Arc

Inside a loop — iterating by value moves the collection on the first pass:

Inside a closure — the compiler message mentions FnOnce:

error[E0382]: use of moved value: `s`
note: closure cannot be invoked more than once because it moves the variable `s` out of its environment

Fix it by borrowing inside the closure (|| println!("{s}") instead of || drop(s)), or by using move deliberately when the closure should own the value.

Returning a field out of a struct — you cannot move one field out of a borrowed struct. Clone the field, or restructure so the function takes ownership.

  • E0505 — cannot move out of a value while it is borrowed
  • E0507 — cannot move out of borrowed content
  • E0597 — borrowed value does not live long enough