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
- Supply a lifetime-shaped name such as `'b` (or plain `b`, which gets an apostrophe added automatically).
- Avoid `_` as a rename target for lifetimes and labels.
- 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
- For lifetime/label targets, restrict input to `'ident` or plain ident (apostrophe added automatically).
- Never offer `_` as a rename target for lifetimes or labels.
- Validate the classification (IdentifierKind) client-side before calling rename.
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
- Cannot rename builtin type
- Cannot rename a builtin attr.
- Cannot rename `Self`
- Invalid name `{0}`: cannot rename module to {0}
- Invalid name `{}`: not an identifier
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/6b96a9d28a0e96b6.
Report an issue: GitHub.