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

  1. Verify you only mutate the tree through the SyntaxEditor API (no direct replacements of the tracked root)
  2. Ensure all edits for an element are applied in the documented order without replacing the root mid-batch
  3. Reproduce with a minimal fixture and file/inspect a bug against rust-analyzer's syntax_editor if reachable from public API
  4. 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

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


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