Rust

Cannot move out of borrowed content cannot move out of behind a shared reference

27 September 2026 · 7 min read

Cannot move out of borrowed content  cannot move out of behind a shared reference

Navigating Rust’s ownership and borrowing system can feel like learning a new language within programming itself. One of the most common and often perplexing errors new Rustaceans encounter is “cannot move out of borrowed content” or “cannot move out of behind a shared reference.” This error message isn’t just a cryptic warning; it’s Rust’s compiler safeguarding against fundamental memory safety issues that plague other languages, such as use-after-free bugs or data races. Understanding this error is crucial to mastering Rust’s core principles and writing safe, efficient code. This article will demystify these messages, explore their root causes in Rust’s unique memory management model, and provide actionable strategies to resolve them effectively, turning frustration into a deeper understanding of Rust’s powerful guarantees.

Understanding Rust’s Ownership and Borrowing System

At the heart of Rust’s renowned memory safety is its ownership system. Every value in Rust has a single owner, and when that owner goes out of scope, the value is dropped, and its memory is automatically deallocated. This strict rule eliminates the need for garbage collectors or manual memory management, preventing entire classes of bugs. However, programs rarely operate on isolated data; they often need to share or temporarily access data owned by other parts of the code. This is where borrowing comes in.

Borrowing allows you to create references to data without taking ownership. Think of it like lending a book: you get to read it, but you don’t own it, and eventually, you must return it. Rust enforces strict rules around these references, known as the “borrowing rules”:

  • At any given time, you can have either one mutable reference (&mut T) OR any number of immutable references (&T).
  • References must always be valid. They cannot outlive the data they refer to.

These rules are enforced at compile time, ensuring that data is never accessed after it’s been freed or modified unexpectedly by multiple parts of the program simultaneously. The “cannot move out of borrowed content” error arises precisely because moving a value implies transferring its ownership, which directly conflicts with the temporary, non-owning nature of a borrow. When you have a borrow, you’re merely looking at or temporarily modifying the data, not claiming it as your own to move elsewhere.

Why You Cannot Move Out of Borrowed Content

The “cannot move out of borrowed content” error is a direct consequence of Rust’s design philosophy: guaranteeing memory safety without a garbage collector. When you borrow a piece of data, the borrower does not become its owner; it merely gets temporary access. Moving a value, on the other hand, means transferring ownership from one variable to another. This act invalidates the original binding and, crucially, would lead to a “use-after-free” bug if a reference to the original data still existed and was later used.

Consider a scenario where you have a struct and you’ve borrowed a mutable reference to it. If you were then allowed to “move” one of its fields out of the struct, that field would no longer exist at its original memory location. Any existing references to that field, or even the struct itself, would become dangling pointers, leading to undefined behavior if accessed. Rust’s compiler diligently prevents this by disallowing moves out of any borrowed content, whether the borrow is shared (immutable) or mutable. This robust check ensures that all references remain valid and point to existing, properly owned data, upholding the integrity of your program’s memory state. According to the official Rust Book, “The borrow checker ensures that borrows do not outlive the data they borrow, and that mutable borrows are exclusive.”

It’s important to differentiate between moving and copying. Primitive types like integers, booleans, and fixed-size arrays implement the Copy trait. For these types, when you assign them to a new variable or pass them to a function, a bit-for-bit copy is made instead of a move. This means the original value remains valid. However, for types that do not implement Copy (e.g., String, Vec, custom structs), assignment or function calls result in a move, transferring ownership and invalidating the original variable. When data is borrowed, neither a move nor a copy (unless it’s a primitive type that implicitly copies) can occur if it would invalidate the borrowed content.

Visualizing Rust Ownership & Borrowing

Infographic explaining Rust ownership, borrowing, and move semanticsThis infographic would illustrate how data is owned, how references are created, and the implications of moving or cloning data within Rust’s memory model.

Common Scenarios and Code Examples ----------------------------------

The “cannot move out of borrowed content” error typically surfaces when you try to extract a part of a borrowed value, effectively trying to take ownership of it. Let’s look at some prevalent situations where this occurs and how to understand the compiler’s complaint.

Moving a Field from a Borrowed Struct

A classic example involves a struct with a non-Copy field. If you have a mutable reference to Question & Answer :

I don’t understand the error cannot move out of borrowed content. I have received it many times and I have always solved it, but I’ve never understood why.

For example:

for line in self.xslg_file.iter() { self.buffer.clear(); for current_char in line.into_bytes().iter() { self.buffer.push(*current_char as char); } println!("{}", line); } 

produces the error:

error[E0507]: cannot move out of borrowed content --> src/main.rs:31:33 | 31 | for current_char in line.into_bytes().iter() { | ^^^^ cannot move out of borrowed content 

In newer versions of Rust, the error is

error[E0507]: cannot move out of `*line` which is behind a shared reference --> src/main.rs:31:33 | 31 | for current_char in line.into_bytes().iter() { | ^^^^ move occurs because `*line` has type `std::string::String`, which does not implement the `Copy` trait 

I solved it by cloning line:

for current_char in line.clone().into_bytes().iter() { 

I don’t understand the error even after reading other posts like:

What is the origin of this kind of error?

Let’s look at the signature for into_bytes:

fn into_bytes(self) -> Vec<u8> 

This takes self, not a reference to self (&self). That means that self will be consumed and won’t be available after the call. In its place, you get a Vec<u8>. The prefix into_ is a common way of denoting methods like this.

I don’t know exactly what your iter() method returns, but my guess is that it’s an iterator over &String, that is, it returns references to a String but doesn’t give you ownership of them. That means you cannot call a method that consumes the value.

As you’ve found, one solution is to use clone. This creates a duplicate object that you do own, and can call into_bytes on. As other commenters mention, you can also use as_bytes which takes &self, so it will work on a borrowed value. Which one you should use depends on your end goal for what you do with the pointer.

In the larger picture, this all has to do with the notion of ownership. Certain operations depend on owning the item, and other operations can get away with borrowing the object (perhaps mutably). A reference (&foo) does not grant ownership, it’s just a borrow.

Why is it interesting to use self instead of &self in a function’s arguments?

Transferring ownership is a useful concept in general - when I am done with something, someone else may have it. In Rust, it’s a way to be more efficient. I can avoid allocating a copy, giving you one copy, then throwing away my copy. Ownership is also the most permissive state; if I own an object I can do with it as I wish.


Here’s the code that I created to test with:

struct IteratorOfStringReference<'a>(&'a String); impl<'a> Iterator for IteratorOfStringReference<'a> { type Item = &'a String; fn next(&mut self) -> Option<Self::Item> { None } } struct FileLikeThing { string: String, } impl FileLikeThing { fn iter(&self) -> IteratorOfStringReference { IteratorOfStringReference(&self.string) } } struct Dummy { xslg_file: FileLikeThing, buffer: String, } impl Dummy { fn dummy(&mut self) { for line in self.xslg_file.iter() { self.buffer.clear(); for current_char in line.into_bytes().iter() { self.buffer.push(*current_char as char); } println!("{}", line); } } } fn main() {}