rust-lang/rust-analyzer · error
an edit target must still be present
Error message
an edit target must still be present
What it means
`map_original_element` translates an element's structural path from the original tree through the recorded edits and resolves it against the current root. The `expect` asserts the library's bookkeeping guarantees that any element being targeted by an edit still exists in the current tree. If path adjustment (`adjust_for_splice` returning None, or `ReplaceRoot`) or resolution fails, internal edit tracking has a bug.
Source
Thrown at crates/syntax/src/syntax_editor/edit_algo.rs:418
fn map_original_path(&self, mut path: SyntaxPath) -> Option<SyntaxPath> {
for edit in &self.edits {
match edit {
PathEdit::Splice { parent, deleted, inserted } => {
if !path.adjust_for_splice(parent, deleted, *inserted) {
return None;
}
}
PathEdit::ReplaceRoot => return None,
}
}
Some(path)
}
/// Finds a change target in the current root.
fn map_original_element(&self, element: &SyntaxElement) -> SyntaxElement {
self.map_original_path(SyntaxPath::new(element))
.and_then(|path| path.resolve(&self.root))
.expect("an edit target must still be present")
}
/// Applies one child-list splice and updates tracked structural path.
fn splice(
&mut self,
parent_path: SyntaxPath,
deleted: Range<usize>,
inserted: Vec<PreparedElement>,
track_as_changed: bool,
) {
let inserted_count = inserted.len();
self.changed
.retain_mut(|path| path.adjust_for_splice(&parent_path, &deleted, inserted_count));
self.annotations
.retain_mut(|it| it.path.adjust_for_splice(&parent_path, &deleted, inserted_count));
for (offset, element) in inserted.iter().enumerate() {
let index = deleted.start + offset;View on GitHub (pinned to e8f7e90aa3)
Solutions
- Verify you only mutate the tree through the SyntaxEditor API (no direct replacements of the tracked root)
- Ensure all edits for an element are applied in the documented order without replacing the root mid-batch
- Reproduce with a minimal fixture and file/inspect a bug against rust-analyzer's syntax_editor if reachable from public API
- When editing internals, make `map_original_element` return `Option<SyntaxElement>` and handle the missing target gracefully
Example fix
// before
.and_then(|path| path.resolve(&self.root))
.expect("an edit target must still be present")
// after
match path.resolve(&self.root) {
Some(element) => element,
None => return None, // or stdx::never! + safe fallback
} Defensive patterns
Strategy: fallback
Validate before calling
// User-facing: ensure edits are applied only via the editor API and the root // is not replaced mid-batch. assert!(editor.root().ancestors().count() > 0, "root must remain live during apply");
Try / catch
// Since this is a panic, isolate edit application:
std::panic::catch_unwind(AssertUnwindSafe(|| editor_map_element(&element)))
.map_err(|_| "edit target lost; rebuild editor from fresh tree") Prevention
- Do not replace the editor root while tracked edits are pending
- Apply all edits through SyntaxEditor; avoid mixing raw tree mutations with tracked edits
- Pin the rust-analyzer version and check its issue tracker before assuming user error — this expect should be unreachable from the public API
When it happens
Trigger: Internal: replaying recorded splices deletes/moves the very element being looked up (tracking missed a splice), or the root was replaced (`PathEdit::ReplaceRoot`) making the original path unresolvable. As an API user this should be unreachable; it surfaces only if SyntaxEditor bookkeeping has a bug or edits are applied out of the API's contract.
Common situations: Practically seen only when hacking on crates/syntax syntax_editor internals, applying an element's edits after the root was fully replaced, or interleaving manual tree mutations with editor-tracked edits.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- reachable plan nodes are not discarded
- syntax annotation id overflow
- equivalent ancestor node should be present in target tree
- the nearest mapped ancestor must map its descendants
- We explicitly do not provide canonicalization API, as that i
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/c6f7c83a933536a2.
Report an issue: GitHub.