Skip to content
Free public beta until December 4, 2026: every course is open, no card needed. After that, the first chapter of each course stays free and full access is a one-time $39 ($19 for up to 100 founding members chosen for helpful feedback). Your progress is kept. How the beta works

Recipe

Fix a lifetime error

Use when: rustc reports E0597, E0515, E0716 or E0499 around a borrow, or says a lifetime may not live long enough, and you're tempted to add or change annotations

Goal: a program whose ownership really keeps every reference valid, with a signature that says only what's true

Taught in Common lifetime errors

  1. 1

    Read the error's labels: which value is borrowed, where it's dropped, and where the late use is.

    Example

    In the quotes program, rustc's E0597 has three labels. line is borrowed on line 11, by line.split_once(": "). It is dropped on line 14, the loop's closing }. The late use is &quotes on line 15. So each Quote points into a line that is gone before the quotes are printed.

    Why: every lifetime error is a reference that would outlive its value, or a claim that it could; you need both ends before choosing a fix.

  2. 2

    Decide who should own the data for as long as it's needed.

    Example

    This is E0597, and line dies at the end of each loop pass. Move the owner outward: before the loop, build let lines: Vec<String> = raw.iter().map(|r| r.to_uppercase()).collect();, then loop with for line in &lines. The text now lives until the end of main, and the program prints ANN said WE SAIL AT DAWN.

    • the data was created inside a function (E0515) — return it owned.
    • the data is a temporary (E0716) — give it a name with let.
    • the data dies each loop pass or in an inner block (E0597) — own a copy, move the owner outward, or use the reference sooner.

    Why: lifetimes never extend anything, so the only real fixes change ownership, placement, or the uses.

  3. 3

    If the error is inside a function body, or calls are rejected that should work, compare each 'a with what the body really returns.

    Example

    Words::next_word(&'a mut self) -> Option<&'a str> compiles, but two calls in a row give E0499. The body returns a slice of the text, not of self. So the 'a on self says something untrue. Remove it: fn next_word(&mut self) -> Option<&'a str>. Both calls now work, and the program prints Some("north") Some("by").

    • an input tied to the output that is never returned — remove its 'a.
    • &'a mut self on a type with lifetime 'a — use &mut self.

    Why: an annotation that claims too much makes correct calls fail; one that claims too little makes the body fail.

  4. 4

    Add or change annotations only to state a relationship the code already has (section 2's recipe).

    Example

    fn normalized(name: &str) -> &str returns &lower, a new String, and gets E0515. Writing fn normalized<'a>(name: &'a str) -> &'a str changes nothing: still E0515. The result is not a piece of name, so there is no true relationship to write down. Step 2's fix is the real one: return String.

    Why: an annotation added to silence an error either moves the error elsewhere or makes the function uncallable.

Common mistakes

  • Adding 'static because rustc mentioned it.
  • Adding 'a to more parameters until the error moves.
  • Cloning inside a function to dodge an error at a call site, when the call site is what's wrong.