sinelaw/fresh · error

Buffer not found

Error message

Buffer not found

What it means

apply_lsp_text_edits maps LSP edits onto a specific buffer before applying them as a bulk edit. When the target buffer_id is not present in the app's buffer map (it was closed or the id is stale), it returns io::ErrorKind::NotFound 'Buffer not found' instead of silently skipping edits.

Solutions

  1. Look up the buffer by URI and re-open it if it was closed before applying edits
  2. Check self.buffers().contains_key(&buffer_id) before requesting/applying edits
  3. Drop or log the edits if the buffer no longer exists instead of failing the whole flow
  4. Use IncrementalTextDocumentSync or re-request formatting after reopening

Example fix

// before
app.apply_formatting_edits(buffer_id, edits)?; // NotFound if closed
// after
if app.buffer_exists(buffer_id) {
    app.apply_formatting_edits(buffer_id, edits)?;
} else {
    log::info!("buffer {buffer_id} closed; discarding formatting edits");
}
Defensive patterns

Strategy: validation

Validate before calling

fn can_apply(app: &App, buffer_id: BufferId) -> bool { app.buffers().contains_key(&buffer_id) }

Try / catch

match app.apply_lsp_text_edits(buffer_id, edits) { Err(e) if e.kind() == io::ErrorKind::NotFound => log::info!("buffer gone; dropping edits"), other => other?, }

Prevention

When it happens

Trigger: Applying completion additional edits, formatting edits, workspace edits, or textDocument edits whose buffer was closed between the LSP request and the response; a server replying with edits for the wrong/unregistered buffer URI.

Common situations: User closes a file while a slow format-on-save or workspace-wide rename is in flight; LSP server sends edits for an unsaved/virtual buffer never opened by the client; stale buffer ids after restart of the language server.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/f6fe6dde954026da. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/src/app/lsp_requests.rs:2632

                        .expect("active window must have a populated split layout")
                        .active_split()
                });
            self.windows
                .get(&self.active_window)
                .and_then(|w| w.buffers.splits())
                .map(|(_, vs)| vs)
                .expect("active window must have a populated split layout")
                .get(&split_id)
                .map(|vs| vs.cursors.primary_id())
                .unwrap_or_else(|| self.active_cursors().primary_id())
        };

        // Create events for all edits
        for edit in edits {
            let state = self
                .buffers_mut()
                .get_mut(&buffer_id)
                .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "Buffer not found"))?;

            // Convert LSP range to byte positions
            let start_line = edit.range.start.line as usize;
            let start_char = edit.range.start.character as usize;
            let end_line = edit.range.end.line as usize;
            let end_char = edit.range.end.character as usize;

            let start_pos = state.buffer.lsp_position_to_byte(start_line, start_char);
            let end_pos = state.buffer.lsp_position_to_byte(end_line, end_char);
            let buffer_len = state.buffer.len();

            // Log the conversion for debugging
            let old_text = if start_pos < end_pos && end_pos <= buffer_len {
                state.get_text_range(start_pos, end_pos)
            } else {
                format!(
                    "<invalid range: start={}, end={}, buffer_len={}>",
                    start_pos, end_pos, buffer_len

View on GitHub (pinned to 67894ca546)