TL;DR
Somewhere in your code there's a reference (&T) inside a struct field, a function signature, or an impl block โ and Rust can't figure out how long it lives. The fix is a named lifetime parameter like 'a. It tells the compiler exactly how the reference's validity relates to the surrounding type or function.
// Before (breaks)
struct Config {
name: &str, // error[E0106]: missing lifetime specifier
}
// After (fixed)
struct Config<'a> {
name: &'a str,
}
What triggers this error
Rust tracks how long every reference is valid โ that's its memory-safety guarantee, enforced at compile time. When a reference appears in a struct field or a function signature with multiple references, the compiler needs explicit guidance: a lifetime annotation that tells it which reference outlives which.
Three spots trigger this most often:
- A struct field that holds a reference (
&str,&T) - A function that returns a reference and takes multiple reference parameters
- An
implblock for a struct that has lifetime parameters
Rust's lifetime elision rules handle many straightforward cases automatically. They don't cover every pattern, though โ and when elision can't resolve it, you get error[E0106].
Fix 1 โ Struct with a reference field
This is the most common trigger. Add a lifetime parameter to the struct, then annotate each reference field with it.
// Broken
struct Article {
title: &str,
body: &str,
}
// Fixed
struct Article<'a> {
title: &'a str,
body: &'a str,
}
Any code that creates or uses an Article now carries the lifetime โ but in practice, the compiler handles most call sites automatically via elision:
fn print_article(article: &Article) { // Rust elides here โ fine
println!("{}", article.title);
}
fn main() {
let title = String::from("Rust Lifetimes");
let body = String::from("They keep you safe.");
let article = Article {
title: &title,
body: &body,
};
print_article(&article);
}
Fix 2 โ Function returning a reference
Returning a reference from a function requires Rust to know which input it came from. One input reference? Elision handles it. Two or more? You annotate explicitly.
// Broken โ Rust can't tell if the return borrows from `a` or `b`
fn longest(a: &str, b: &str) -> &str {
if a.len() > b.len() { a } else { b }
}
// Fixed โ both inputs share lifetime 'a, output lives at most as long
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.len() > b.len() { a } else { b }
}
The 'a annotation says: "the returned reference is valid for as long as both a and b are valid." In practice, that means the shorter of the two lifetimes wins.
Fix 3 โ impl block for a struct with lifetimes
Methods on a lifetime-parameterized struct need the same lifetime on the impl keyword itself. Forgetting it is an easy mistake to make.
struct Parser<'a> {
input: &'a str,
pos: usize,
}
// Broken
impl Parser {
fn remaining(&self) -> &str {
&self.input[self.pos..]
}
}
// Fixed
impl<'a> Parser<'a> {
fn remaining(&self) -> &str {
&self.input[self.pos..]
}
}
Fix 4 โ Consider owning the data instead
Sometimes lifetimes are the wrong tool altogether. If adding 'a everywhere makes the code harder to follow, just own the data outright:
// Instead of borrowing a &str...
struct Config<'a> {
name: &'a str,
}
// ...own a String
struct Config {
name: String,
}
You pay a small heap allocation, but the struct is simpler and far easier to pass around. That trade-off usually wins unless you're in a hot path or working directly with borrowed slices from an external API.
Verify the fix
Rebuild the project:
cargo build
No error[E0106] in the output means the lifetimes are resolved. While you're at it, run Clippy to catch any lifetime anti-patterns the compiler might have let through:
cargo clippy
Still unsure which annotation to use? Ask the compiler directly:
rustc --explain E0106
That command prints the full explanation with examples โ right in your terminal, no browser needed.
Quick decision guide
- Struct with
&stror&Tfields โ add<'a>to the struct and annotate the field. - Function returning a reference with multiple input references โ annotate which input the output borrows from.
- impl block on a struct with lifetimes โ mirror the lifetime params on
impl<'a> MyStruct<'a>. - Everything else โ consider switching to owned types (
Stringinstead of&str,Vec<T>instead of&[T]).

