Mehdi Akiki
Rust Failure Atlas / Runtime, memory, and library APIs

RFA-508 · Case file with fixtures · Case 480 of 694 · Compiler evidence

Rust Reference Fields Must Declare Who Keeps the Data Alive

A struct that stores a reference is valid only while its referent remains alive. A lifetime parameter records that relationship; ownership types remove it by moving or sharing the data instead.

Reviewed
Rust
Rust 1.98.1, edition 2024
Targets
all Rust targets
Profiles
dev, release, test

Direct answer

What this Rust failure means

Why it happens
The View value depends on storage owned elsewhere, and without a lifetime parameter its type does not record that it must stop being used before the text owner.
First discriminating check
Identify the data owner and desired flow, then declare the borrow lifetime or choose owned/shared storage rather than reaching for static as an escape hatch.

I wrote struct View { text: &str }. Rust emitted E0106 because the struct stores a borrow but does not state how the validity of that borrow relates to the lifetime of the struct value.

The failing fixture is not missing memory allocation. It is missing a relationship: every View must stop being usable before the borrowed text becomes invalid.

A stored reference carries a lifetime

References always have lifetimes, even when syntax elides them in permitted contexts. For a field, Rust needs the containing type to expose the relationship explicitly, commonly as View<'a> { text: &'a str }.

This does not make the data live longer. It lets the borrow checker compare the lifetime chosen for a particular View with the owner of the referenced text.

The official E0106 page shows the parameter on both the type and field.

The repaired fixture borrows from an owner

The repaired fixture creates an owned String, then constructs a View borrowing from it. Because the owner remains in scope while the view is read, the relationship is valid.

If I attempted to return the view after dropping owned, the named lifetime would not rescue it. Rust would reject that escape. Lifetime annotations describe constraints; they are not commands to extend storage duration.

This is the most important correction when learning this diagnostic.

Function lifetime elision is deliberately limited

The Reference on lifetime elision permits common function signatures to omit names under specific rules. A single borrowed input can determine an output borrow, and a method receiver can determine it in another rule.

Struct fields do not have a function call whose inputs establish the relation. The type can be instantiated in many scopes, so it needs a parameter to carry the borrow duration.

I do not assume syntax accepted in function parameters is accepted in stored type definitions.

Owning the data removes the borrow parameter

If a view must outlive its current source or move freely between long-lived tasks, storing String may be better. Shared ownership with Arc<str> can fit read-only data used across threads, while Cow<'a, str> supports borrowed or owned cases under one interface.

Each choice has allocation, cloning, lifetime, and API costs. I select ownership based on how values flow, not because lifetime syntax feels difficult.

Borrowing is excellent when an existing owner clearly outlives the view.

Multiple fields can share or separate lifetimes

Two reference fields may use one lifetime when both must be valid for the whole view. Separate lifetime parameters can admit values borrowed from owners with different durations.

Using one lifetime is simpler but can make the shorter borrow constrain the entire value. Using several adds type complexity. I model the relationships callers need rather than giving every field a unique name automatically.

Methods can then return references tied to the appropriate field or receiver lifetime.

Static is not the default repair

Writing &'static str works only for data valid for the whole program, such as many string literals or intentionally leaked allocations. It rejects ordinary borrowed String content and may encourage leaks.

I use 'static when it is a true invariant, not as a way to remove E0106. Most request views, parser slices, and temporary projections need a generic lifetime.

Self-referential ownership needs another design

Adding a lifetime parameter does not let a struct own a String and store a normal reference into that same string safely through straightforward construction. Moving the struct could change where owned data lives, and initialization temporarily lacks a complete owner.

I usually store indexes or ranges into the owned buffer, recompute slices when needed, or use a purpose-built pinned abstraction with carefully reviewed invariants. For parsing, separating the input owner from borrowed views is often simpler. E0106 is about borrowing from another owner, not a recipe for self-reference.

My E0106 checklist

  • Which owner contains the referenced data?
  • How long must the struct value remain usable?
  • Does the type declare a lifetime parameter for that relation?
  • Would owning String, Arc<str>, or Cow better fit the flow?
  • Do several fields need one shared lifetime or separate ones?
  • Am I expecting annotations to extend the owner's lifetime?
  • Does function elision apply here, or is this a stored field?
  • Is 'static a real invariant rather than an escape hatch?

The core principle is that a reference field makes the containing value depend on another owner. The lifetime parameter records that dependency so Rust can prevent the view from surviving its data.