Skip to content

Misleading "Lifetime Must Outlive x" Diagnostic #147564

@Philogy

Description

@Philogy

Code

fn filter_guest_list_and_add_bob<'bob, 'guests: 'bob>(
    guests: Vec<&'guests str>,
    bob: &'bob str,
) -> Vec<&'guests str> {
    let mut filtered: Vec<&'guests str> = Vec::new();
    for g in guests {
        if g.starts_with("vip") {
            filtered.push(g);
        }
    }
    filtered.push(bob);
    filtered
}

Current output

error: lifetime may not live long enough
 --> src/main.rs:5:23
  |
1 | fn filter_guest_list_and_add_bob<'bob, 'guests: 'bob>(
  |                                  ----  ------- lifetime `'guests` defined here
  |                                  |
  |                                  lifetime `'bob` defined here
...
5 |     let mut filtered: Vec<&'guests str> = Vec::new();
  |                       ^^^^^^^^^^^^^^^^^ type annotation requires that `'bob` must outlive `'guests`
  |
  = help: consider adding the following bound: `'bob: 'guests`

error: aborting due to 1 previous error

Desired output

error: lifetime may not live long enough
  --> src/main.rs:11:23
   |
 1 | fn filter_guest_list_and_add_bob<'bob, 'guests: 'bob>(
   |                                  ----  ------- lifetime `'guests` outlives `'bob`
   |                                  |
   |                                  lifetime `'bob` defined here
...
11 |     filtered.push(bob);
   |                   ^^^ `filtered` requires values that live at least as long as `'guests` but `'guests` outlive `'bob`
   |

Rationale and extra context

If I mix incompatible lifetimes at the use of a function/method I expect to have that location highlighted in the diagnostic so I can see whether the definition or use is wrong. This is what "normal type errors" already do:

For example if I swap the lifetimes & strings for types u32 & u16 I get a much more intuitive error highlighting which line caused filtered to be inferred as u32 and then a subsequent type mismatch at the site of the second push:

fn filter_guest_list_and_add_bob(guests: Vec<u32>, bob: u16) -> Vec<u32> {
    let mut filtered = Vec::new();
    for g in guests {
        if g < 100 {
            filtered.push(g);
        }
    }
    filtered.push(bob);
    filtered
}

More intuitive error:

error[E0308]: mismatched types
    --> src/main.rs:8:19
     |
   5 |             filtered.push(g);
     |             --------      - this argument has type `u32`...
     |             |
     |             ... which causes `filtered` to have type `Vec<u32>`
...
   8 |     filtered.push(bob);
     |              ---- ^^^ expected `u32`, found `u16`
     |              |
     |              arguments to this method are incorrect
     |
note: method defined here
    --> /Users/philogy/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:2521:12
     |
2521 |     pub fn push(&mut self, value: T) {
     |            ^^^^
help: you can convert a `u16` to a `u32`
     |
   8 |     filtered.push(bob.into());
     |                      +++++++

error: aborting due to 1 previous error

Other cases

Rust Version

rustc 1.90.0 (1159e78c4 2025-09-14)
binary: rustc
commit-hash: 1159e78c4747b02ef996e55082b704c09b970588
commit-date: 2025-09-14
host: aarch64-apple-darwin
release: 1.90.0
LLVM version: 20.1.8

Anything else?

Even more confusing I get the same error but at the return expression if I don't add an explicit type:

fn filter_guest_list_and_add_bob<'bob, 'guests: 'bob>(
    guests: Vec<&'guests str>,
    bob: &'bob str,
) -> Vec<&'guests str> {
    let mut filtered = Vec::new();
    for g in guests {
        if g.starts_with("vip") {
            filtered.push(g);
        }
    }
    filtered.push(bob);
    filtered
}

Error:

error: lifetime may not live long enough
  --> src/main.rs:12:5
   |
 1 | fn filter_guest_list_and_add_bob<'bob, 'guests: 'bob>(
   |                                  ----  ------- lifetime `'guests` defined here
   |                                  |
   |                                  lifetime `'bob` defined here
...
12 |     filtered
   |     ^^^^^^^^ function was supposed to return data with lifetime `'guests` but it is returning data with lifetime `'bob`
   |
   = help: consider adding the following bound: `'bob: 'guests`

error: aborting due to 1 previous error

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-lifetimesArea: Lifetimes / regionsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions