rust-lang/rust-analyzer · error
inconsistent text range
Error message
inconsistent text range
What it means
During prepare_rename, rust-analyzer collects every candidate definition found at the cursor position and requires all of them to resolve to the exact same text range, since a single rename target must be produced. When two or more overlapping definitions at the offset map to different ranges, the reduce step cannot pick one and bails with this error. It indicates an ambiguity in resolution at that position that the rename feature cannot handle.
Source
Thrown at crates/ide/src/rename.rs:105
.filter(|(_, _, def, _, _)| def.range_for_rename(&sema).is_some())
.map(|(frange, kind, _, _, _)| {
always!(
frange.range.contains_inclusive(position.offset)
&& frange.file_id == position.file_id
);
Ok(match kind {
SyntaxKind::LIFETIME => {
TextRange::new(frange.range.start() + TextSize::from(1), frange.range.end())
}
_ => frange.range,
})
})
.reduce(|acc, cur| match (acc, cur) {
// ensure all ranges are the same
(Ok(acc_inner), Ok(cur_inner)) if acc_inner == cur_inner => Ok(acc_inner),
(e @ Err(_), _) | (_, e @ Err(_)) => e,
_ => bail!("inconsistent text range"),
});
match res {
// ensure at least one definition was found
Some(res) => res.map(|range| RangeInfo::new(range, ())),
None => bail!("No references found at position"),
}
}
// Feature: Rename
//
// Renames the item below the cursor and all of its references
//
// | Editor | Shortcut |
// |---------|----------|
// | VS Code | <kbd>F2</kbd> |
//
// View on GitHub (pinned to e8f7e90aa3)
Solutions
- Move the cursor precisely onto the identifier token (not adjacent punctuation or macro input) and retry prepare_rename.
- Resolve the ambiguity in the source: avoid shadowed or macro-expanded bindings at that position.
- If this is a rust-analyzer bug, reproduce with a minimal fixture and report; meanwhile rely on the editor's fallback (find references + manual rename).
Example fix
// before (ambiguous: shadowed binding under cursor)
let x = 1; { macro_rules! m { () => { let x = 2; x } } m!(); }
// after: disambiguate position or name
let x = 1; { let y = 2; y }
Defensive patterns
Strategy: validation
Validate before calling
// Client-side: ensure the offset lands on an identifier character
let line_chars: Vec<char> = line.chars().collect();
let on_ident = offset_in_line <= line_chars.len()
&& line_chars.get(offset_in_line.saturating_sub(1))
.map_or(false, |c| c.is_alphanumeric() || *c == '_' || *c == '\'');
if !on_ident { /* do not call prepare_rename */ } Type guard
fn is_on_ident(line: &str, col: usize) -> bool {
line.chars().nth(col.saturating_sub(1))
.map_or(false, |c| c.is_alphanumeric() || c == '_' || c == '\'')
} Try / catch
match prepare_rename(db, pos) {
Ok(range_info) => show_rename(range_info),
Err(e) if e.to_string().contains("inconsistent text range") => {
fallback_to_find_references(pos); // ambiguous target
}
Err(e) => report(e),
} Prevention
- Only invoke rename/prepare_rename with the cursor directly on an identifier token
- Avoid renaming inside macro-generated or desugared spans
- Sync document content with the server before sending rename requests
- Treat rename failures as non-fatal and fall back to search-and-replace
When it happens
Trigger: Calling prepare_rename (via the textDocument/rename prepare LSP request) at a cursor offset where find_definitions yields multiple definitions whose range_for_rename differs — e.g. positions where name classification is ambiguous (macro-expanded names, overlapping shadowed bindings, or attribute/macro-generated tokens resolving to distinct defs).
Common situations: Renaming an identifier that sits inside macro-generated or desugared code where the same token resolves to several defs; IDE plugin requests at ambiguous positions in edition-ambiguous files; typically hit by editor users pressing F2 on tricky code rather than by library consumers directly.
Related errors
- No file available to rename
- No references found at position
- Cannot rename builtin type
- Invalid name `{}`: cannot rename to a keyword
- Invalid name `{}`: {}
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/552ffb1765987472.
Report an issue: GitHub.