rust-lang/rust-analyzer · error

Invalid name `{0}`: cannot rename module to {0}

Error message

Invalid name `{0}`: cannot rename module to {0}

What it means

`rename_mod` classifies the proposed new name via `IdentifierKind::classify` and only accepts a plain identifier for modules. If the new name is not an `Ident` (e.g. a lifetime, `_`, or `self`), it fails with "Invalid name ... cannot rename module to {0}" because module names must be valid non-underscore identifiers.

Source

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

    }
}

fn rename_mod(
    sema: &Semantics<'_, RootDatabase>,
    module: hir::Module,
    new_name: &str,
) -> Result<SourceChange> {
    let mut source_change = SourceChange::default();

    if module.is_crate_root(sema.db) {
        return Ok(source_change);
    }

    let InFile { file_id, value: def_source } = module.definition_source(sema.db);
    let edition = file_id.edition(sema.db);
    let (new_name, kind) = IdentifierKind::classify(edition, new_name)?;
    if kind != IdentifierKind::Ident {
        bail!(
            "Invalid name `{0}`: cannot rename module to {0}",
            new_name.display(sema.db, edition)
        );
    }
    if let ModuleSource::SourceFile(..) = def_source {
        let anchor = file_id.original_file(sema.db).file_id(sema.db);

        let is_mod_rs = module.is_mod_rs(sema.db);
        let has_detached_child = module.children(sema.db).any(|child| !child.is_inline(sema.db));

        // Module exists in a named file
        if !is_mod_rs {
            let path = format!("{}.rs", new_name.as_str());
            let dst = AnchoredPathBuf { anchor, path };
            source_change.push_file_system_edit(FileSystemEdit::MoveFile { src: anchor, dst })
        }

        // Rename the dir if:

View on GitHub (pinned to e8f7e90aa3)

Solutions

  1. Provide a valid Rust identifier as the new module name (letters/digits/underscores, not starting with a digit, not `_` or `self`).
  2. If the desired name contains dashes or spaces (e.g. from a directory name), convert it to snake_case first.
  3. Pre-validate the name in the client with an identifier check before issuing the rename request.

Example fix

// before
rename(mod_def, "my-mod")?; // invalid: not an Ident
// after
rename(mod_def, "my_mod")?; // valid snake_case identifier
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_mod_name(name: &str) -> bool {
    !name.is_empty()
        && name != "_"
        && name != "self"
        && !name.starts_with('\'')
        && name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
        && !name.chars().next().unwrap().is_ascii_digit()
}

Type guard

fn is_plain_ident(s: &str) -> bool {
    syn::parse_str::<syn::Ident>(s).is_ok() && s != "self" && s != "_"
}

Try / catch

match def.rename(sema, new_name, ...) {
    Err(e) if e.to_string().contains("cannot rename module to") => eprintln!("module names must be plain identifiers"),
    other => other?,
}

Prevention

When it happens

Trigger: Renaming a `Definition::Module` whose new name classifies as `Lifetime`, `Underscore`, or `LowercaseSelf` — e.g. `rename(mod_def, "'a")`, `rename(mod_def, "_")`, or `rename(mod_def, "self")`.

Common situations: User selects a module declaration and types `self`, `_`, or a quoted/lifetime-like string in the rename input box; the IDE rejects it.

Related errors


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