Rust Error E0597 Borrowed Value Does Not Live Long Enough
E0597 means a reference outlives the value it points to. See the two common shapes, a block that ends too early and a struct that outlives its data, and how to fix each.

error[E0597]: ... does not live long enough says you have a reference to a value that is destroyed before the reference's last use. In C this is a dangling pointer, and the program reads freed or reused stack memory with no complaint. In Rust the compiler rejects it and prints the three lines you need: where the value was declared, where it was dropped, and where the reference is used afterward. This post reproduces the three situations that produce this error most often, shows the compiler's real output on Rust 1.99, and shows the fix for each, which is nearly always the same idea: make the value live as long as the reference, or make the reference own its data.
What the error means
Every value lives from the line that creates it to the end of the block that owns it, where it is dropped. A reference is only valid while the value it points to is alive. The compiler checks that every reference's lifetime fits inside the lifetime of its target. When it does not, you get E0597, and the three annotations in the output describe the violation exactly: the binding, the point where it dies, and the use after death.
Form one: a reference that escapes its block
The textbook version has an inner scope:
fn main() {
let r;
{
let x = 5;
r = &x;
}
println!("r: {r}");
}error[E0597]: `x` does not live long enough
--> e0597a.rs:5:13
|
4 | let x = 5;
| - binding `x` declared here
5 | r = &x;
| ^^ borrowed value does not live long enough
6 | }
| - `x` dropped here while still borrowed
7 | println!("r: {r}");
| - borrow later used hereRead the three annotated lines as a timeline. x is created on line 4. On line 6 the closing brace drops it. On line 7 r, which still points at x, is used. The program would read a dead variable. The fix is to widen the lifetime of the value so it outlives the use, by declaring it in the same scope:
fn main() {
let x = 5;
let r = &x;
println!("r: {r}");
}r: 5Real programs rarely have a bare inner block like this, but they have equivalents everywhere: a variable created inside an if branch, a match arm, a loop body, or a helper function whose result is stored somewhere longer-lived. The pattern to look for is a reference stored in a variable declared outside the block and a value created inside it.
Form two: a struct that borrows something shorter-lived
The second form is a struct with a lifetime parameter, such as a parser that holds a slice of its input:
struct Parser<'a> {
input: &'a str,
}
fn main() {
let parser;
{
let text = String::from("let x = 1;");
parser = Parser { input: &text };
}
println!("{}", parser.input);
}error[E0597]: `text` does not live long enough
--> e0597b.rs:9:34
|
8 | let text = String::from("let x = 1;");
| ---- binding `text` declared here
9 | parser = Parser { input: &text };
| ^^^^^ borrowed value does not live long enough
10 | }
| - `text` dropped here while still borrowed
11 | println!("{}", parser.input);
| ------------ borrow later used hereThe 'a in Parser<'a> is a promise that the struct does not outlive the text it points into. Here the parser outlives the String it borrows, which is precisely the promise broken. The fix is the same as before: declare the owner first, so it lives at least as long as the borrower. Rust drops locals in reverse order of declaration, so the borrowed value must come first:
struct Parser<'a> {
input: &'a str,
}
fn main() {
let text = String::from("let x = 1;"); // declared first, so it outlives the parser
let parser = Parser { input: &text };
println!("{}", parser.input);
}let x = 1;When the parser has to be returned from a function that created the text, you cannot borrow, because the text dies at the end of the function. Make the struct own its data (input: String) and pay the allocation once, or take the text as a parameter so the caller owns it. The choice is a design decision about who owns the input, and the lifetime error is the compiler asking you to make it.
Form three: a collection of references to loop-local values
The version that catches people in real code stores references in a map or vector that outlives the loop that fills it:
use std::collections::HashMap;
fn main() {
let mut index: HashMap<&str, usize> = HashMap::new();
for i in 0..3 {
let key = format!("item-{i}");
index.insert(&key, i);
}
println!("{}", index.len());
}error[E0597]: `key` does not live long enough
--> e0597c.rs:7:22
|
6 | let key = format!("item-{i}");
| --- binding `key` declared here
7 | index.insert(&key, i);
| ^^^^ borrowed value does not live long enough
8 | }
| - `key` dropped here while still borrowed
9 | println!("{}", index.len());
| ----- borrow later used hereEach iteration creates a new String called key and drops it at the end of the iteration. The map holds &str keys that point into those dropped strings. After the loop, every key in the map would be a dangling reference. The honest fix is to let the map own its keys:
use std::collections::HashMap;
fn main() {
let mut index: HashMap<String, usize> = HashMap::new();
for i in 0..3 {
let key = format!("item-{i}");
index.insert(key, i); // the map owns the key now
}
println!("{}", index.len());
}3The change from HashMap<&str, usize> to HashMap<String, usize> is where the data lives. A map of borrowed keys is fine when the keys come from a source that lives longer, such as slices of a big input text read once at the start. When the keys are created along the way, the map must own them.
A fourth form: returning a reference to a local
A function cannot return a reference to something it created. The compiler reports that one as E0515 ("cannot return value referencing local variable") rather than E0597, but it is the same idea. This function uppercases its input and returns the longest line, as a slice into the uppercased copy:
fn longest_line(text: &str) -> &str {
let upper = text.to_uppercase();
upper.lines().max_by_key(|l| l.len()).unwrap_or("")
}error[E0515]: cannot return value referencing local variable `upper`
--> e0515.rs:3:5
|
3 | upper.lines().max_by_key(|l| l.len()).unwrap_or("")
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `upper` is borrowed hereThe signature promises a &str borrowed from the input text, but the slice points into upper, a new String that is freed when the function returns. The honest signature returns an owned String, because the result is new data and not a view of the input:
fn longest_line(text: &str) -> String {
text.to_uppercase().lines().max_by_key(|l| l.len()).unwrap_or("").to_string()
}A LONGER LINEThe general rule for return types: if the result is a piece of an input, return a reference and tie it to that input; if the function creates the data, return an owned value. A reference return type is a statement about where the data lives, and a function that builds data cannot make that statement.
Choosing the fix
| Symptom | Fix |
|---|---|
| Value declared in an inner block, reference used outside | Move the declaration out so the owner is declared first |
| Struct with a lifetime, outlived by the data it borrows | Declare the data before the struct, or make the struct own it |
| Collection of references filled with loop-local values | Store owned values, String instead of &str |
| Function returning a reference to its own local | Return the owned value, or accept the owner as a parameter |
Do not reach for 'static or Box::leak to silence the error. They make the compiler quiet by keeping the data alive forever, which turns a compile-time error into a memory leak. And do not add lifetime annotations hoping the compiler will relent; a lifetime annotation describes a relationship, it never extends how long a value lives. The value lives exactly as long as its owner does, and the error is telling you the owner is too short.
For the surrounding concepts, see ownership in Rust explained, and for the other two errors in this family, E0382, use of a moved value and E0502, mutable and immutable borrows.


