How to fix Rust E0507 cannot move out of dereference of shared reference

Fix Rust E0507 by using a mutable reference to move the value or cloning the data instead of moving from a shared reference.

The shared reference trap

You're writing a function to extract a value from a struct. You pass a reference to keep the original data safe. Inside the function, you try to return the field as an owned value. The compiler stops you with E0507. It feels like Rust is blocking a simple operation. It's not. It's preventing you from tearing a hole in your data structure.

This error appears when you try to move a value out of a shared reference (&T). Rust forbids this because a shared reference implies the value is owned by someone else. Moving the value would leave the owner with garbage. The compiler catches this at compile time so you never get a dangling reference at runtime.

What the compiler is protecting you from

A shared reference is a view, not a handle. It guarantees the value exists and won't change while you look at it. It does not give you permission to modify the source or take ownership.

Think of a shared reference like a window into a room. You can see the furniture. You can take a photo of the furniture. You cannot reach through the window and carry the sofa away. If you could, the room would be empty, but the window would still show the sofa. That's a lie. Rust refuses to let you create a lie in your memory model.

The deeper reason involves aliasing. A shared reference allows multiple references to point to the same data at the same time. If you move a value through one shared reference, you invalidate the source. Any other shared reference now points to memory that no longer holds the value. This is undefined behavior. Rust eliminates this class of bugs by making the move illegal.

A shared reference is a promise of stability. Moving breaks that promise. The compiler enforces the promise.

Minimal reproduction

Here is the smallest case that triggers the error. You have a struct with a String. You try to extract the string through a shared reference.

struct User {
    name: String,
}

fn get_name(user: &User) -> String {
    // E0507: cannot move out of `user.name`
    // `user` is a shared reference. Rust guarantees the owner still has `name`.
    // Moving it would leave the owner with a hole.
    user.name
}

The compiler rejects this with E0507 (cannot move out of dereference of shared reference). It points to user.name and explains that you're trying to move out of a borrowed value. The fix depends on what you're trying to achieve.

Why this happens under the hood

When you access user.name, the compiler sees a field access on a reference. If name is a String, the field itself is a value type. Returning it as String requires moving the String out of the struct.

Moving involves copying the pointer and length from the struct to the return value, and marking the source as invalid. You can't mark the source as invalid through a shared reference. The shared reference has no authority to modify the struct. Only the owner, or a mutable reference, can modify the struct.

This is why &T and moving are incompatible. &T means "I can read, but I can't change the owner's state." Moving changes the owner's state by removing the value. The types don't match the capabilities.

Real-world fixes

In practice, you encounter this error when processing collections, caches, or configuration structs. You need to get data out, but the signature only gives you a shared reference. Here are the standard ways to resolve it.

Clone the value

If the value is cheap to copy, clone it. This creates an independent copy without touching the original.

fn get_name_clone(user: &User) -> String {
    // Clone creates a new String with its own heap allocation.
    // The original `user.name` remains untouched.
    user.name.clone()
}

Cloning is safe and simple. It allocates memory and copies data. Use it when the cost is acceptable. For small strings or integers, the cost is negligible. For large buffers, cloning can hurt performance.

Switch to a mutable reference

If you need to extract the value and you control the caller, change the signature to accept &mut T. A mutable reference grants exclusive access. You can modify the source.

fn take_name(user: &mut User) -> String {
    // `&mut` allows moving out of fields.
    // The compiler knows no other references exist.
    std::mem::take(&mut user.name)
}

This requires the caller to pass a mutable reference. It signals that the function consumes the value. The caller must handle the fact that user.name is now empty.

Use std::mem::take

When you have a mutable reference but the type is complex, std::mem::take is the idiomatic tool. It swaps the value with a default placeholder and returns the original value.

use std::mem;

fn drain_cache(cache: &mut Vec<String>) -> Vec<String> {
    // `take` swaps the vec with an empty vec.
    // This avoids cloning the entire vector.
    // The cache is left in a valid, empty state.
    mem::take(cache)
}

Community convention prefers std::mem::take over std::mem::replace when the type implements Default. It's concise and signals that you're draining the value. You're taking the data and leaving a valid placeholder behind.

The Option extraction idiom

A common pattern in Rust is wrapping fields in Option to allow extraction. Option::take moves the value out and sets the field to None.

struct Config {
    token: Option<String>,
}

impl Config {
    fn consume_token(&mut self) -> Option<String> {
        // `take` extracts the value if present.
        // The field becomes `None`.
        // This works with `&mut self`.
        self.token.take()
    }
}

Wrapping fields in Option solely for extraction is a standard idiom. It adds a tiny bit of overhead but enables move semantics through mutable references. It's useful for one-time consumption patterns, like draining a queue or consuming a credential.

Don't fight the borrow checker by cloning everything. Change the signature or use mem::take to extract safely.

Pitfalls and edge cases

Cloning when you should borrow

A common mistake is cloning a value just to satisfy the compiler, when borrowing would suffice. If you only need to read the data, change the return type to a reference.

fn get_name_ref(user: &User) -> &str {
    // Return a reference to the string data.
    // No allocation. No move.
    &user.name
}

Borrowing is free. Moving is expensive. If the caller doesn't need ownership, don't give it to them. Return a reference.

E0507 vs E0502

E0507 often appears alongside E0502 (cannot borrow as mutable because it is also borrowed as immutable). If you try to mutate a value while a shared reference exists, you hit E0502. If you try to move through a shared reference, you hit E0507. Both errors stem from the same rule: shared references forbid mutation. Moving is a form of mutation.

E0507 in closures

Closures capture variables by reference by default. If a closure tries to move a captured value, you get E0507.

let data = vec![1, 2, 3];
let _f = || {
    // E0507: cannot move out of `data`
    // The closure captures `&data`.
    // Moving requires `&mut data` or `data` by value.
    data
};

Fix this by capturing by value (move closure) or by cloning inside the closure.

let data = vec![1, 2, 3];
let _f = move || {
    // `move` forces the closure to take ownership of `data`.
    // Moving is now allowed.
    data
};

Interior mutability

If you have shared ownership but need mutation, consider interior mutability types like RefCell<T> or Mutex<T>. These allow mutation through shared references by checking borrow rules at runtime.

use std::cell::RefCell;

struct SharedData {
    value: RefCell<String>,
}

fn update(data: &SharedData) {
    // `RefCell` allows mutation through `&`.
    // Borrow checking happens at runtime.
    data.value.borrow_mut().clear();
}

Interior mutability is a trade-off. You gain flexibility but lose compile-time guarantees. Use it when the borrow checker is too restrictive for your design, not as a first resort.

Decision matrix

Use clone() when the value is small and you need an independent copy without modifying the source. Use &mut T when you control the caller and can pass a mutable reference, allowing direct extraction. Use std::mem::take when you need to extract a value from a mutable reference and the type implements Default, leaving a valid placeholder behind. Use Option::take when the field is wrapped in Option and you want to consume the value while setting the source to None. Reach for borrowing when you only need to read the data; changing the return type to &T avoids the move entirely and keeps the original intact.

Trust the error. E0507 means you're about to leave a hole in someone's data. Fix the ownership, don't bypass it.

Where to go next