Rust Error E0106: Missing Lifetime Specifier
Error E0106 means: you wrote a reference (&) in a function’s return type or a struct, and Rust can’t tell what it borrows from. It’s not a bug in your logic. The compiler just needs one more word from you, or a small change of plan. Almost everyone meets this error in their first week, and the fix is usually a single line. (This page is part of Rust compiler errors explained.)
The error message
Section titled “The error message”error[E0106]: missing lifetime specifier --> src/main.rs:1:32 |1 | fn longer(a: &str, b: &str) -> &str { | ---- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`help: consider introducing a named lifetime parameter |1 | fn longer<'a>(a: &'a str, b: &'a str) -> &'a str { | ++++ ++ ++ ++The program that causes it:
fn longer(a: &str, b: &str) -> &str { if a.len() >= b.len() { a } else { b }}
fn main() { println!("{}", longer("apple", "fig"));}What it means
Section titled “What it means”A reference is a borrow: it points at data that somebody else owns. Whenever a function returns a reference, Rust needs to know whose data it points into, so it can check that the data stays alive while the caller uses the result.
Look at the three marks under line 1. The compiler underlines a and b with ---- and the return type with ^. It is saying: “you return a borrowed &str, and it could come from a or from b. Which one?” It won’t guess.
Think of a library card. If a friend hands you a book and says “it’s borrowed”, you want to know from whom, so you know when it must go back. A lifetime is that label on the borrow.
Why Rust does this
Section titled “Why Rust does this”Rust guarantees that a reference can never outlive the data it points to (no “dangling pointers”). To check that for a function call, the compiler only looks at the function’s signature, not its body. So the signature itself must say where the returned reference comes from.
Most of the time you never write lifetimes, because Rust fills them in with three simple elision rules:
- Each reference parameter gets its own lifetime.
- If there is exactly one reference parameter, the returned reference borrows from it.
- If it’s a method with
&selfor&mut self, the returned reference borrows fromself.
E0106 appears when none of these rules gives an answer: two or more reference parameters (and no self), zero reference parameters, or a reference stored in a struct. The Lifetimes lesson covers this in depth, and Borrowing explains references themselves.
How to fix it
Section titled “How to fix it”Fix 1: Add a named lifetime ('a)
Section titled “Fix 1: Add a named lifetime ('a)”Choose this when the function really does return a piece of one of its inputs. 'a is just a name. Writing it on the inputs and the output says “the result lives as long as these inputs”:
// 'a: the returned &str borrows from a or b, so it lives as long as both.fn longer<'a>(a: &'a str, b: &'a str) -> &'a str { if a.len() >= b.len() { a } else { b }}
fn main() { let first = String::from("apple"); let second = String::from("fig"); println!("Longer word: {}", longer(&first, &second));}Output:
Longer word: appleIf the result only ever comes from one parameter, put 'a on that parameter only: fn lookup<'a>(map: &'a HashMap<String, String>, key: &str) -> Option<&'a str>. The compiler’s suggestion puts 'a on everything, which works but is stricter than needed.
Fix 2: Return an owned String instead
Section titled “Fix 2: Return an owned String instead”Choose this when the function builds new text, or when you just don’t want the caller tied to a borrow. An owned String belongs to the caller, so there is nothing to track:
fn greeting(name: &str, lang: &str) -> String { if lang == "es" { format!("Hola, {name}!") } else { format!("Hello, {name}!") }}
fn main() { println!("{}", greeting("Ana", "es")); println!("{}", greeting("Sam", "en"));}Output:
Hola, Ana!Hello, Sam!This costs one small allocation. For most programs that’s completely fine. Don’t feel bad about it.
Fix 3: Store owned data in your struct
Section titled “Fix 3: Store owned data in your struct”A struct field like title: &str gives the same error:
error[E0106]: missing lifetime specifier --> src/main.rs:2:12 |2 | title: &str, | ^ expected named lifetime parameterFor structs, the best fix is nearly always to own the data: use String instead of &str, and Vec<T> instead of &[T]. Then the struct can live as long as you like:
#[derive(Debug)]struct Book { title: String, // owned, not &str pages: u32,}
fn main() { let book = Book { title: String::from("Dune"), pages: 412 }; println!("{} ({} pages)", book.title, book.pages);}Output:
Dune (412 pages)Only give a struct a lifetime when it is a short-lived view into data that lives somewhere else, like a parser looking at a big text. Then you write <'a> on the struct and on the field:
struct Excerpt<'a> { text: &'a str, // borrows from the novel below}
fn main() { let novel = String::from("Call me Ishmael. Some years ago..."); let first = novel.split('.').next().unwrap(); let excerpt = Excerpt { text: first }; println!("Excerpt: {}", excerpt.text);}Output:
Excerpt: Call me IshmaelFix 4: Use 'static for string literals
Section titled “Fix 4: Use 'static for string literals”When a function has no reference parameters at all, the error says “there is no value for it to be borrowed from”:
error[E0106]: missing lifetime specifier --> src/main.rs:1:22 |1 | fn default_name() -> &str { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed fromIf you only return string literals like "OK", write &'static str. Literals are baked into your program, so they live for the whole run:
fn status_text(code: u16) -> &'static str { match code { 200 => "OK", 404 => "Not Found", _ => "Unknown", }}
fn main() { println!("200 means {}", status_text(200)); println!("404 means {}", status_text(404));}Output:
200 means OK404 means Not FoundUse 'static only for real literals and constants. If the text is built at runtime (with format!, or read from a file), 'static won’t help: return a String (Fix 2).
Where you’ll usually see it
Section titled “Where you’ll usually see it”- Helper functions with two inputs, like
fn lookup(map: &HashMap<String, String>, key: &str) -> Option<&str>. Fix: tie the output tomaponly with'a(Fix 1). - Structs that hold text, like a
User { name: &str }built from parsed input. Fix: useStringfields (Fix 3). - Functions returning fixed messages, like
fn error_label() -> &str. Fix:&'static str(Fix 4).
Methods are the good news: fn name(&self) -> &str needs no lifetime at all, thanks to rule 3.
Related errors
Section titled “Related errors”- E0382: borrow of moved value: another ownership error, about using a value after giving it away.
- E0502: mutable borrow while immutably borrowed: the borrow checker at work once your lifetimes are in place.
- E0499: two mutable borrows: two
&mutto the same data at once. - E0308: mismatched types: for example, returning
Stringfrom a function that says&str. E0515: cannot return reference to local variable: you tried Fix 1 on data created inside the function. Return an ownedStringinstead (Fix 2).- All compiler errors explained
Quick check
Section titled “Quick check”Quick check
1. Why does fn first_word(s: &str) -> &str compile without any lifetime?
2. Your struct Config { path: &str } gives E0106. What's usually the best fix?
3. A function builds a message with format! and returns it. What return type should it have?
Score: 0 / 3
Read more
Section titled “Read more”- E0106 — Rust error codes index: the official explanation of this error.
- Validating References with Lifetimes — The Rust Book: the full story of lifetimes, including the
longestexample and structs with references. - Lifetime elision — The Rust Reference: the exact rules Rust uses to fill in lifetimes for you.
- Elision — Rust by Example: short examples of when you can leave lifetimes out.
- Lifetimes — Rust by Example: runnable examples of explicit lifetimes in functions, methods and structs.