Common Ownership Compiler Errors
When a program violates one of Rust's ownership rules, rustc rejects the code at compile time with a specific E0xxx error code and suggests how to fix it.
Quick Reference of Ownership Error Codes
| Error Code | Diagnostic Headline | Root Cause | Standard Fix |
|---|---|---|---|
E0382 |
borrow / use of moved value |
Using a non-Copy variable after moving its ownership elsewhere |
Pass a reference (&x), clone explicitly (x.clone()), or reorder usages |
E0507 |
cannot move out of ... which is behind a shared/mutable reference |
Trying to move a non-Copy value (String) out of *r, &struct.field, or &vec[i] |
Borrow the field (&r.field), .clone() it, or use std::mem::take on &mut |
E0508 |
cannot move out of type '[T; N]', a non-copy array |
Indexing let elem = arr[i]; by value on an array of non-Copy items |
Borrow &arr[i], use std::mem::take(&mut arr[i]), or destructure let [a, b] = arr; |
E0509 |
cannot move out of type 'T', which implements the 'Drop' trait |
Moving a single field out of a struct that has a custom impl Drop |
Borrow &s.field, .clone() the field, or wrap the field in Option<Field> and call .take() |
E0040 |
explicit use of destructor method |
Calling x.drop() directly instead of drop(x) |
Call drop(x) (std::mem::drop(x)) |
1. Use of Moved Value Inside a Loop (E0382)
A frequent way to trigger E0382 is moving an outer non-Copy variable inside a loop body. Even if the variable is initialized before the loop starts, the first iteration moves it, leaving it uninitialized on the second iteration:
// ❌ does not compile
fn consume(s: String) {
println!("{s}");
}
fn main() {
let prefix = String::from("item");
for i in 0..3 {
consume(prefix); // Moved on iteration 0; uninitialized on iteration 1!
println!("{i}");
}
}
error[E0382]: use of moved value: `prefix`
--> src/main.rs:9:17
|
6 | let prefix = String::from("item");
| ------ move occurs because `prefix` has type `String`, which does not implement the `Copy` trait
7 |
8 | for i in 0..3 {
| ------------- inside of this loop
9 | consume(prefix);
| ^^^^^^ value moved here, in previous iteration of loop
error: aborting due to 1 previous error
Fix: Change consume to borrow s: &str (consume(&prefix)), or pass consume(prefix.clone()) if each iteration genuinely requires an independent owned String.
2. Moving Out of an Indexed Vec<T> or Slice (E0507)
Because indexing a vector (vec[i]) actually calls Index::index(&vec, i) -> &T and dereferences the returned reference (*vec.index(i)), writing let item = vec[0]; on a Vec<String> attempts to move out of a reference and fails with E0507:
// ❌ does not compile
fn main() {
let list = vec![String::from("alpha"), String::from("beta")];
let first: String = list[0];
}
error[E0507]: cannot move out of index of `Vec<String>`
--> src/main.rs:3:25
|
3 | let first: String = list[0];
| ^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
3 | let first: &String = &list[0];
| +
error: aborting due to 1 previous error
Fixes when you need an owned String from Vec<String>:
fn main() {
let mut list = vec![
String::from("alpha"),
String::from("beta"),
String::from("gamma"),
];
// 1. Borrow without moving (`&String`):
let borrowed: &String = &list[0];
println!("Borrowed: '{borrowed}'");
// 2. Remove and take ownership in O(1) by swapping with the last element:
let owned_first: String = list.swap_remove(0);
println!("Extracted via swap_remove(0): '{owned_first}', remaining: {list:?}");
}
Borrowed: 'alpha'
Extracted via swap_remove(0): 'alpha', remaining: ["gamma", "beta"]