How to fix cannot move out of borrowed content

Fix the 'cannot move out of borrowed content' error by passing ownership directly or cloning the data instead of trying to move from a reference.

The "Cannot Move Out of Borrowed Content" Error

You are writing a function that processes a configuration object. The object holds an API key as a String. You pass a reference to the config into the function because the caller needs to use the config afterward. Inside the function, you try to extract the API key to store it in a log struct. The compiler rejects the code with E0507: cannot move out of borrowed content.

This error happens when you try to take ownership of data that lives inside a value you are only borrowing. Rust forbids this because moving data transfers ownership. If you move data out of a borrowed value, the original value is left with a hole or a dangling pointer. The owner of that value expects it to remain valid, but your move would invalidate it. The compiler blocks the move to prevent memory corruption.

Ownership versus borrowing

Rust tracks who owns every piece of data. The owner is responsible for cleaning up the data when it goes out of scope. You can hand ownership to someone else by moving the value. You can also lend the value by creating a reference. A reference is a view. It lets you look at the data without taking responsibility for it.

When you have a reference, you do not own the data. You cannot transfer ownership of the data because you don't have it to give. Moving data out of a reference would create two owners for the same heap allocation. When the first owner drops, the memory gets freed. The second owner is left pointing at garbage. Accessing that memory causes a crash or a security vulnerability.

Think of a library book. You can borrow the book to read it. While you have the book, you cannot rip out a chapter and sell it to someone else. The library still owns the book. If you ripped out the chapter, the book would be damaged, and the library would be upset. You can photocopy the chapter (clone), or you can buy the whole book (take ownership). You cannot extract the chapter and keep the book intact.

Minimal example

Here is the smallest case that triggers the error. A struct holds a String. A function takes a shared reference to the struct. The function tries to move the String out.

struct Config {
    api_key: String,
}

fn log_key(config: &Config) {
    // E0507: cannot move out of `config.api_key` which is behind a shared reference
    let key = config.api_key;
    
    println!("Key: {}", key);
}

The compiler stops you at let key = config.api_key. The variable config is a &Config. Accessing config.api_key through a shared reference yields a &String. You cannot convert a &String into a String by moving. The move operation requires ownership. The compiler sees that you are trying to take the heap pointer out of the struct, but the struct is owned by someone else.

What happens under the hood

A String is a small struct on the stack containing a pointer to heap memory, a length, and a capacity. When you move a String, Rust copies those three words. The pointer now belongs to the new variable. The old variable is marked as invalid.

If Rust allowed you to move config.api_key while config is a reference, the heap pointer would be copied to key. The config struct would still exist and still hold the old pointer. When log_key returns, config goes out of scope. The owner of the original Config drops it. The drop implementation frees the heap memory. The variable key now holds a pointer to freed memory. Using key later reads garbage or crashes.

The error E0507 is the compiler's way of saying: "You are trying to duplicate the pointer and leave the original in a broken state. I won't let you do that."

Realistic scenario: processing a list

This error often appears when working with collections. You have a list of items. You pass the list to a function that needs to process each item. The items contain owned data. You try to extract that data.

struct Task {
    id: u32,
    payload: Vec<u8>,
}

fn process_tasks(tasks: &Vec<Task>) {
    for task in tasks {
        // E0507: cannot move out of `task.payload` which is behind a shared reference
        let data = task.payload;
        
        // Do something with data...
    }
}

The loop gives you task as a &Task. You cannot move payload out of task. The Vec<Task> owns the tasks. The function only borrows the vector. Moving the payload would invalidate the task, which is still part of the vector.

Fixing the error

There are four standard ways to resolve this error. The right choice depends on whether you need an owned copy, whether you can change the function signature, and whether the data is expensive to copy.

Clone the data

If you need an owned copy and the cost is acceptable, clone the data. Cloning creates a new allocation and copies the contents. The original remains untouched.

fn log_key(config: &Config) {
    // Clone creates a new String with its own heap allocation.
    // The original config.api_key remains valid.
    let key = config.api_key.clone();
    
    println!("Key: {}", key);
}

Cloning is safe and simple. It allocates memory and copies bytes. For small strings, the cost is negligible. For large payloads, cloning can be expensive. Use cloning when the data is small or when the logic requires an independent copy.

Convention aside: calling clone() is explicit. Rust developers expect clone() to allocate. If you see clone(), you know a copy is happening. Don't hide clones inside helper functions without documenting them.

Borrow the data instead

If the function only needs to read the data, change the function to accept a reference. This avoids copying entirely.

fn log_key(config: &Config) {
    // Take a reference to the String.
    // key is a &String, which coerces to &str.
    let key = &config.api_key;
    
    println!("Key: {}", key);
}

This works when the downstream code accepts a reference. If log_key needs to store the key in a struct that requires an owned String, borrowing won't work. You must clone or take ownership.

Convention aside: prefer &str over &String in function signatures. &str is a slice that can point to a String or a string literal. It is more flexible. Write fn log_key(key: &str) instead of fn log_key(key: &String).

Take ownership

If the function is the final consumer of the data, change the signature to take ownership. This moves the value into the function. The caller no longer has access to the data.

fn log_key(config: Config) {
    // config is owned. Moving api_key out is allowed.
    let key = config.api_key;
    
    println!("Key: {}", key);
}

This is the most efficient option. No allocation, no copying. The data moves directly into the function. Use this when the caller does not need the data afterward.

If the caller needs the data but you want to avoid cloning, you can return the data back. This is rare and usually indicates a design issue. Prefer cloning or borrowing.

Use Cow for flexibility

Cow stands for "Clone on Write". It is an enum that can hold either a borrowed reference or an owned value. It lets you accept both owned and borrowed data. You only clone if you need to mutate the data.

use std::borrow::Cow;

fn process_key(key: Cow<'_, str>) {
    // If key is borrowed, we can use it directly.
    // If we need to modify it, we clone into an owned String.
    let owned_key = key.into_owned();
    
    println!("Key: {}", owned_key);
}

Cow is useful in APIs where the caller might pass a &str or a String. The function can work with the borrowed data without cloning. If mutation is needed, the function clones at that point. This avoids unnecessary allocations when the data is already owned by the caller.

Pitfalls and compiler errors

E0507 versus E0502

Do not confuse E0507 with E0502. E0507 is about moving out of borrowed content. E0502 is about borrowing as mutable while an immutable borrow exists.

If you see E0507, you are trying to move data. The fix is cloning, borrowing, or taking ownership. If you see E0502, you are trying to mutate data while someone else is reading it. The fix is scoping borrows or using interior mutability.

Removing from collections

You cannot remove items from a collection through a shared reference. Removing an item changes the collection. This requires a mutable reference.

fn remove_first(tasks: &Vec<Task>) {
    // E0596: cannot borrow `*tasks` as mutable, as it is behind a `&` reference
    // Also E0507 if you try to move the removed item.
    let task = tasks.remove(0);
}

The error here is usually E0596 first. You need &mut Vec<Task> to call remove. Once you have a mutable reference, you can remove the item. The removed item is moved out of the vector. This is allowed because you have mutable access.

Partial moves

Rust allows moving individual fields out of a struct if you have ownership of the struct. This is called a partial move. The struct becomes partially moved. You cannot use the struct as a whole anymore, but you can use the fields that were not moved.

fn extract_key(config: Config) -> String {
    // config is owned. Moving api_key is allowed.
    let key = config.api_key;
    
    // config is now partially moved.
    // You cannot use config as a whole.
    // You can still use config if it has other fields that were not moved.
    
    key
}

Partial moves do not work through references. You cannot partially move a struct through &Config or &mut Config. Moving a field out through a reference would leave the struct in an invalid state. The compiler forbids this.

Decision matrix

Use clone() when you need an owned copy and the data is small enough that the allocation cost is acceptable. Use clone() when the logic requires an independent value that outlives the original.

Use &T or &str when you only need to read the data and the lifetime of the reference is sufficient. Use references to avoid allocations and keep data localized.

Use T (ownership) when the function is the final consumer of the data and the caller does not need it afterward. Use ownership to move data efficiently without copying.

Use Cow<T> when you want to accept both owned and borrowed data and only clone if mutation is required. Use Cow in library APIs to give callers flexibility without forcing allocations.

Use &mut T when you need to modify the data in place or remove items from a collection. Use mutable references to change data without taking ownership.

Where to go next