Skip to content
Select theme

How to fix error E0597: borrowed value does not live long enough

Short answer: a reference outlived the value it points to. The error prints three locations — where the value is borrowed, where it is dropped, and where the borrow is used later — and every fix moves one of those three points: keep the value alive longer, use the borrow earlier, or store an owned value instead.

Compiling that with cargo build prints:

error[E0597]: `x` does not live long enough
--> src/main.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 is {r}");
| - borrow later used here
For more information about this error, try `rustc --explain E0597`.

The error is made of three markers, and reading them in order answers the question the title asks — how long is long enough?

  • Line 5, the borrow. r = &x creates a reference to x, and the compiler immediately asks: how long will this reference be used?
  • Line 7, the use. borrow later used here marks the println! that dereferences r. This is the moment that keeps the borrow alive.
  • Line 6, the drop. `x` dropped here while still borrowed marks the closing brace where x’s scope ends. This is the deadline.

A reference may not outlive the value it points at. x is born at the top of the inner block and dies at its closing brace; r is still dereferenceable on the println! line after that. If the compiler allowed this, r would point at memory that is already gone, and the whole promise behind references — a &x is always valid to read — would be broken.

The fix: move the drop point, not the borrow

Section titled “The fix: move the drop point, not the borrow”

The borrow is fine; the drop is too early. The note already says which value to keep alive, so the fix is to move x into the scope that needs it:

This prints:

r is 5

Nothing about the borrow changed — only the drop point moved. x now lives in the outer scope, so its scope ends after the last use of r, and the three markers the error printed no longer conflict. That is the general procedure for E0597: read the drop note, find the value it names, and give that value a scope that covers the use note.

The version that catches people: a value created in a loop

Section titled “The version that catches people: a value created in a loop”

The same error, one level more realistic. Collecting references into a collection that outlives the loop looks reasonable, but each iteration’s variables are dropped at the end of that iteration:

error[E0597]: `line` does not live long enough
--> src/main.rs:5:20
|
2 | let mut lines: Vec<&String> = Vec::new();
| --------- variable `lines` declared here
3 | for _ in 0..2 {
4 | let line = String::from("tick");
| ---- binding `line` declared here
5 | lines.push(&line);
| ----- ^^^^^ borrowed value does not live long enough
| |
| borrow later used here
6 | }
| - `line` dropped here while still borrowed
|
= note: `lines` is a collection that stores borrowed references, but `line` does not live long enough to be stored in it
= help: buffer reuse with borrowed references requires unsafe code or restructuring
For more information about this error, try `rustc --explain E0597`.

The three markers are all there again, but the drop note sits on the closing brace of the loop body: line does not die at the end of main, it dies at the end of every iteration. lines, on the other hand, was declared before the loop and is used after it, so every reference stored inside it would be dangling by the time println! reads them. The note: spells out the shape of the conflict: the collection stores borrowed references, and the borrowed value does not live long enough to be stored.

Here moving the drop point is not possible — line is created fresh each iteration, and you cannot declare a loop-local variable outside the loop it depends on. The fix is to stop borrowing: store owned values instead, and let the collection take the data itself.

This prints:

["tick", "tick"]

The reference asked the collection to remember where line lived; the owned String hands the collection its data instead, and there is nothing left to dangle. This is the other common resolution of E0597: when the borrowed value genuinely cannot live longer — a loop local, a temporary, something owned elsewhere — the borrow is the thing to remove, not the scope.

“Long enough” means until the last use

Section titled ““Long enough” means until the last use”

One subtlety the three markers make visible: the value does not have to live until the end of the function, only until the last time the reference is used. The borrow later used here marker is what pins the deadline — remove that use and the borrow ends there too. This is why moving code around can fix E0597 without touching any declaration: pull the use above the drop, or drop the reference when you are done with it, and the conflict disappears. Where a reference has to be declared before its value exists — the let r; at the top of the first example — the borrow still cannot start before the value does, which is exactly what the compiler counted against it here.

Two neighbours that look similar but carry different codes:

  • Dropping or moving the value by hand while a borrow is alive — drop(name); or passing the value to a function that consumes it — is E0505 (cannot move out of value because it is borrowed). There the scope is fine; an explicit move beat the deadline.
  • When the borrowed value is a temporary that vanishes at the end of the very statement that created it, the code is E0716 (temporary value dropped while borrowed). Same shape of problem, but the value never had a binding at all.