rust-lang/rust-analyzer · error

Invalid name `{}`: not an identifier

Error message

Invalid name `{}`: not an identifier

What it means

For non-lifetime definitions, `rename_reference` requires the classified name to be `Ident` or `Underscore`. A lifetime-shaped name (starts with `'`, classified `IdentifierKind::Lifetime`) is invalid for ordinary identifiers, so the rename bails with "Invalid name `{}`: not an identifier". `cov_mark::hit!(rename_not_an_ident_ref)` marks this path in tests.

Source

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

                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));
            }
            IdentifierKind::Ident => cov_mark::hit!(rename_non_local),
            IdentifierKind::Underscore => (),
            IdentifierKind::LowercaseSelf => {
                bail!(
                    "Invalid name `{}`: cannot rename to `self`",
                    new_name.display(sema.db, edition)
                );
            }
        }
    }

    let def = convert_to_def_in_trait(sema.db, def);
    let usages = def.usages(sema).all();

    if !usages.is_empty() && ident_kind == IdentifierKind::Underscore {
        cov_mark::hit!(rename_underscore_multiple);
        bail!("Cannot rename reference to `_` as it is being referenced multiple times");

View on GitHub (pinned to e8f7e90aa3)

Solutions

  1. Remove the leading apostrophe and pass a plain identifier (e.g. `y` instead of `'y`).
  2. If renaming a lifetime was intended, place the cursor on the lifetime parameter first.
  3. Client-side, strip or reject names beginning with `'` when the target is not a lifetime.

Example fix

// before
rename(local_def, "'a")?; // Err: not an identifier
// after
rename(local_def, "a")?; // ok
Defensive patterns

Strategy: validation

Validate before calling

if !is_lifetime_target(def) && new_name.starts_with('\'') {
    return Err(anyhow!("identifiers must not start with an apostrophe"));
}

Type guard

fn is_plain_identifier(s: &str) -> bool {
    let mut cs = s.chars();
    matches!(cs.next(), Some(c) if c.is_ascii_alphabetic() || c == '_') && cs.all(|c| c.is_ascii_alphanumeric() || c == '_')
}

Try / catch

match def.rename(sema, new_name, ...) {
    Err(e) if e.to_string().contains("not an identifier") => eprintln!("drop the leading apostrophe for non-lifetime names"),
    other => other?,
}

Prevention

When it happens

Trigger: Renaming any non-lifetime `Definition` (e.g. a local variable, function, or module) with a lifetime-shaped new name such as `"'a"` at crates/ide-db/src/rename.rs:382.

Common situations: User selects a variable like `x` and types `'a` into the rename box (often by accidentally leaving an apostrophe from a previous lifetime rename), and the IDE rejects it.

Related errors


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