Email me

Rust errors / Ownership and borrowing

Rust compiler error · checked with rustc 1.99.0

Rust error E0521: borrowed data escapes outside of closure

What it meansA reference is moved somewhere that needs it to live longer than it does, usually into a spawned thread or task that requires 'static data.

What rustc prints

error[E0521]: borrowed data escapes outside of closure
 --> main.rs:6:5
  |
3 | let mut list: Vec<&str> = Vec::new();
  |     -------- `list` declared here, outside of the closure body
4 |
5 | let _add = |el: &str| {
  |             -- `el` is a reference that is only valid in the closure body
6 |     list.push(el); // error: `el` escapes the closure body here
  |     ^^^^^^^^^^^^^ `el` escapes the closure body here
  |
  = note: requirement occurs because of a mutable reference to `Vec<&str>`
  = note: mutable references are invariant over their type parameter
  = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

Real output of rustc 1.99.0 compiling the official example below (2021 edition). Your names and line numbers will differ; the first line is the part to match.

Why it happens

  • tokio::spawn or thread::spawn with a closure that uses &self or another borrowed parameter.

How to fix it

1. Move owned data in

Clone what the task needs, or share it with Arc.

let name = self.name.clone();
tokio::spawn(async move { log(&name).await });

2. Use scoped threads for borrowed data

std::thread::scope(|s| { s.spawn(|| work(&data)); });

Other wordings of this error

borrowed data escapes outside of closure, borrowed data escapes outside of function, argument requires that is borrowed for static

E0521Ownership and borrowing
Activein rustc 1.99.0
8related errors linked below

The compiler team's explanation

Borrowed data escapes outside of closure.

Erroneous code example:

let mut list: Vec<&str> = Vec::new();

let _add = |el: &str| {
    list.push(el); // error: `el` escapes the closure body here
};

A type annotation of a closure parameter implies a new lifetime declaration. Consider to drop it, the compiler is reliably able to infer them.

let mut list: Vec<&str> = Vec::new();

let _add = |el| {
    list.push(el);
};

See the Closure type inference and annotation and Lifetime elision sections of the Book for more details.

From rustc --explain E0521 (1.99.0), part of the Rust project, MIT or Apache-2.0. Official page.

Related errors

All 518 Rust error codes · Rust crate data · Glossary

Up next

Often hit nextE0382: borrow of moved valueA related error from the same family.Read it next →

Did this answer your question?

Get the receipts by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Popular in the shop

All 124 tools →

Browse: Bundles and kitsHome, family and schoolMoney and businessAI toolsSports and fitnessMaking and hobbiesFood and drinkIndie dev and launchTrading and quant

Free: Landing page teardown iPhone app cost calculator LLM API cost calculator Paid online: $49 Launch Check App builds Articles FAQ