sinelaw/fresh · error

active window present

Error message

active window present

What it means

Panic from `.expect("active window present")` in `jump_to_bookmark` (bookmark_actions.rs:92). Jumping to a bookmark whose buffer is not the active one checks whether that buffer still exists in the active window's buffer map; the expect asserts the active window exists. It panics if the bookmark action is dispatched while `self.active_window` does not resolve to an entry in `self.windows`.

Solutions

  1. Replace the expect with a guard: if the active window is missing, either drop the action or show the 'buffer gone' status message.
  2. Make window close always update `self.active_window` to a remaining window.
  3. Prune bookmarks whose buffer/window no longer exists when windows close.
  4. Add a regression test jumping to a bookmark after closing all windows.

Example fix

// before
.map(|w| &w.buffers)
.expect("active window present")
.contains_key(&bookmark.buffer_id)
// after
let Some(active) = self.windows.get(&self.active_window) else {
    self.set_status_message(t!("bookmark.buffer_gone", key = key).to_string());
    return;
};
if active.buffers.contains_key(&bookmark.buffer_id) { ... }
Defensive patterns

Strategy: validation

Validate before calling

if !self.windows.contains_key(&self.active_window) {
    self.set_status_message(t!("bookmark.buffer_gone", key = key).to_string());
    return;
}

Type guard

fn can_jump_to_bookmark(app: &App, bm: &Bookmark) -> bool {
    app.windows.get(&app.active_window)
        .map(|w| w.buffers.contains_key(&bm.buffer_id))
        .unwrap_or(false)
}

Try / catch

std::panic::catch_unwind(AssertUnwindSafe(|| self.jump_to_bookmark(key))).map_err(|_| self.set_status_message("bookmark unavailable".into()));

Prevention

When it happens

Trigger: `handle_action` dispatches `jump_to_bookmark` for a bookmark with `buffer_id != self.active_buffer()`, and `self.windows.get(&self.active_window)` is None — active window closed/removed but `active_window` still references it.

Common situations: Invoking a bookmark jump via keybinding/command palette right after window teardown; stale bookmark registry pointing into a closed window; action queue replaying actions after window close.

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 sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/3b9369c7bb1f9875. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/src/app/bookmark_actions.rs:92

    ///
    /// Stays on `impl Editor` because the body fires plugin hooks
    /// (`apply_event_to_active_buffer`) and orchestrates cross-cutting
    /// state (active-buffer switch, viewport recentering). Moving it
    /// to `impl Window` waits for plugin-hook firing to be available
    /// from `Window`.
    pub(super) fn jump_to_bookmark(&mut self, key: char) {
        let Some(bookmark) = self.active_window_mut().bookmarks.get(key) else {
            self.set_status_message(t!("bookmark.not_set", key = key).to_string());
            return;
        };

        // Switch to the buffer if needed, or forget the bookmark if it's gone.
        if bookmark.buffer_id != self.active_buffer() {
            if self
                .windows
                .get(&self.active_window)
                .map(|w| &w.buffers)
                .expect("active window present")
                .contains_key(&bookmark.buffer_id)
            {
                self.set_active_buffer(bookmark.buffer_id);
            } else {
                self.set_status_message(t!("bookmark.buffer_gone", key = key).to_string());
                self.active_window_mut().bookmarks.remove(key);
                return;
            }
        }

        // Move cursor to bookmark position
        let cursor = *self.active_cursors().primary();
        let cursor_id = self.active_cursors().primary_id();
        let state = self.active_state_mut();
        let new_pos = bookmark.position.min(state.buffer.len());

        let event = Event::MoveCursor {
            cursor_id,

View on GitHub (pinned to 67894ca546)