← Debugging Guides

阅读中文版本

Rust E0515 — Cannot Return Reference to Local Value

Fix Rust E0515 by returning an owned value instead of a reference to a local, or by returning a borrowed parameter that outlives the function.

beginnerdebuggingrustlifetimese0515

Symptoms

  • error[E0515]: cannot return value referencing local variable `x`
  • The function returns a reference or a struct holding a reference
  • Renaming a binding changes which error appears

Possible causes

  • The returned reference points at a value created inside the function
  • A struct with a reference field is built from a local temporary
  • The lifetime of the return is tied to a local rather than a parameter

Diagnosis steps

Read which local is referenced

cargo build 2>&1 | sed -n "/E0515/,/^$/p"

Interpretation

The note names the local that would be dropped at return, showing what must become owned.

Check the return type signature

grep -n "fn .*-> &" src/lib.rs

Interpretation

Returning &T requires an input &T with a matching lifetime; otherwise return T.

Root cause

A reference must not outlive the value it points to. Returning a reference to a local normally drops that local at function end, so the borrow would dangle; Rust rejects this with E0515.

Fix

Return an owned value (String, Vec, or a struct by value), or change the signature to return a reference to a parameter whose lifetime the caller guarantees, and use lifetime elision or explicit bounds.

Risk note

Adding clone everywhere to satisfy E0515 can be needless; often taking the input by reference and returning that reference avoids the copy.

Verify the fix

cargo build succeeds and the returned value is usable after the call; a test holds the result across a scope boundary to prove no dangling.

Symptoms

This debugging guide addresses “Rust E0515 — Cannot Return Reference to Local Value”. Start from the symptoms, follow the ordered diagnostics, and confirm each hypothesis before moving on; the fix and verification steps then close the loop.

Observed symptoms include:

  • error[E0515]: cannot return value referencing local variable x
  • The function returns a reference or a struct holding a reference
  • Renaming a binding changes which error appears

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Read which local is referenced

cargo build 2>&1 | sed -n "/E0515/,/^$/p"

The note names the local that would be dropped at return, showing what must become owned.

Step 2: Check the return type signature

grep -n "fn .*-> &" src/lib.rs

Returning &T requires an input &T with a matching lifetime; otherwise return T.

Likely contributors, in order of frequency:

  • The returned reference points at a value created inside the function
  • A struct with a reference field is built from a local temporary
  • The lifetime of the return is tied to a local rather than a parameter

Root Cause

A reference must not outlive the value it points to. Returning a reference to a local normally drops that local at function end, so the borrow would dangle; Rust rejects this with E0515.

The Fix

Return an owned value (String, Vec, or a struct by value), or change the signature to return a reference to a parameter whose lifetime the caller guarantees, and use lifetime elision or explicit bounds.

Watch out: Adding clone everywhere to satisfy E0515 can be needless; often taking the input by reference and returning that reference avoids the copy.

// ❌ returns a reference to a local String
// fn name() -> &str {
//     let s = String::from("alice");
//     &s // E0515
// }

// ✅ return owned
fn name() -> String { String::from("alice") }

// ✅ return a reference to an input that outlives the call
fn first_word(s: &str) -> &str {
    s.split_whitespace().next().unwrap_or("")
}

Verify and Prevent

cargo build succeeds and the returned value is usable after the call; a test holds the result across a scope boundary to prove no dangling.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.