rust-lang/rust-analyzer · error

Invalid name `{}`: not a lifetime identifier

Error message

Invalid name `{}`: not a lifetime identifier

What it means

In `rename_reference`, when the definition being renamed is a lifetime parameter or label, the new name must classify as `Lifetime` or `Ident` (an apostrophe is auto-added). Passing `_` classifies as `Underscore`, which is not a valid lifetime identifier, so the rename bails with "Invalid name `{}`: not a lifetime identifier".

Source

Thrown at crates/ide-db/src/rename.rs:364

}

fn rename_reference<'db>(
    sema: &Semantics<'db, RootDatabase>,
    def: Definition<'db>,
    new_name: &str,
    rename_definition: RenameDefinition,
    edition: Edition,
    config: &RenameConfig,
) -> Result<SourceChange> {
    let (mut new_name, ident_kind) = IdentifierKind::classify(edition, new_name)?;

    if matches!(
        def,
        Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
    ) {
        match ident_kind {
            IdentifierKind::Underscore => {
                bail!(
                    "Invalid name `{}`: not a lifetime identifier",
                    new_name.display(sema.db, edition)
                );
            }
            IdentifierKind::Ident => {
                new_name = Name::new_lifetime(&format!("'{}", new_name.as_str()))
            }
            IdentifierKind::Lifetime => (),
            IdentifierKind::LowercaseSelf => bail!(
                "Invalid name `{}`: not a lifetime identifier",
                new_name.display(sema.db, edition)
            ),
        }
    } else {
        match ident_kind {
            IdentifierKind::Lifetime => {
                cov_mark::hit!(rename_not_an_ident_ref);
                bail!("Invalid name `{}`: not an identifier", new_name.display(sema.db, edition));

View on GitHub (pinned to e8f7e90aa3)

Solutions

  1. Supply a lifetime-shaped name such as `'b` (or plain `b`, which gets an apostrophe added automatically).
  2. Avoid `_` as a rename target for lifetimes and labels.
  3. In the client, validate that rename input for lifetimes matches `'?[a-z_][A-Za-z0-9_]*` before calling.

Example fix

// before
rename(lifetime_def, "_")?; // Err: not a lifetime identifier
// after
rename(lifetime_def, "'b")?; // ok
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_lifetime_input(name: &str) -> bool {
    let s = name.strip_prefix('\'').unwrap_or(name);
    !s.is_empty() && s != "_" && s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
}

Type guard

fn is_lifetime_target(def: &Definition) -> bool {
    matches!(def, Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_))
}

Try / catch

match def.rename(sema, new_name, ...) {
    Err(e) if e.to_string().contains("not a lifetime identifier") => eprintln!("use a lifetime name like 'b"),
    other => other?,
}

Prevention

When it happens

Trigger: Renaming a `Definition::GenericParam(LifetimeParam)` or `Definition::Label` while passing the new name `"_"` (classified as `IdentifierKind::Underscore`) at crates/ide-db/src/rename.rs:364.

Common situations: User attempts to rename `'a` to `_` in `fn f<'a>(x: &'a str)` or to rename a loop label `'lbl` to `_`; the IDE rejects the operation.

Related errors


AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03). Data as JSON: /api/errors/6b96a9d28a0e96b6. Report an issue: GitHub.