zellij-org/zellij · error · anyhow::Error
active tab {} does not exist
Error message
active tab {} does not exist What it means
Screen::get_active_tab maps a client's entry in active_tab_ids to a Tab in the tabs BTreeMap. This error means the client's recorded active tab id has no corresponding Tab — the two structures are out of sync, e.g. the tab was closed without updating active_tab_ids for that client.
Source
Thrown at zellij-server/src/screen.rs:4280
Ok(())
}
/// Returns a mutable reference to this [`Screen`]'s tabs.
pub fn get_tabs_mut(&mut self) -> &mut BTreeMap<usize, Tab> {
&mut self.tabs
}
pub fn get_tabs(&self) -> &BTreeMap<usize, Tab> {
&self.tabs
}
/// Returns an immutable reference to this [`Screen`]'s active [`Tab`].
pub fn get_active_tab(&self, client_id: ClientId) -> Result<&Tab> {
match self.active_tab_ids.get(&client_id) {
Some(tab) => self
.tabs
.get(tab)
.ok_or_else(|| anyhow!("active tab {} does not exist", tab)),
None => Err(anyhow!("active tab not found for client {:?}", client_id)),
}
}
pub fn get_client_input_mode(&self, client_id: ClientId) -> Option<InputMode> {
self.get_active_tab(client_id)
.ok()
.and_then(|tab| tab.get_client_input_mode(client_id))
}
pub fn get_first_client_id(&self) -> Option<ClientId> {
self.active_tab_ids.keys().next().copied()
}
/// Returns an immutable reference to this [`Screen`]'s previous active [`Tab`].
/// Consumes the last entry in tab history.
pub fn get_previous_tab(&mut self, client_id: ClientId) -> Result<Option<&Tab>> {
Ok(View on GitHub (pinned to 98a0837077)
Solutions
- Update or clear the client's active tab pointer when closing tabs (set_active_tab / the tab-close handlers) so active_tab_ids never outlives the tab
- Callers should handle the Err and pick a fallback tab (e.g. first key of self.tabs) instead of crashing
- Reproduce and report upstream if a stock keybinding flow leaves the desync behind
Example fix
// before
let tab = screen.get_active_tab(client_id)?;
// after
let tab = screen
.get_active_tab(client_id)
.or_else(|_| screen.get_tabs().values().next().context("no tabs exist"))?; Defensive patterns
Strategy: fallback
Type guard
fn client_tab_alive(active_tab_ids: &HashMap<ClientId, usize>, tabs: &BTreeMap<usize, Tab>, client: ClientId) -> bool {
active_tab_ids.get(&client).map_or(false, |id| tabs.contains_key(id))
} Try / catch
let tab = screen
.get_active_tab(client_id)
.or_else(|_| screen.get_tabs().values().next().context("no tabs exist"))?; Prevention
- Always update active_tab_ids when closing a client's active tab
- Callers of get_active_tab should fall back to the first remaining tab on Err
When it happens
Trigger: Any caller of get_active_tab (rendering, input-mode queries, focus operations) after the tab referenced by active_tab_ids[client_id] was removed from self.tabs — close-tab paths that skip updating the client's active pointer, or a client reconnecting with stale state.
Common situations: Closing the active tab of a client in multi-client sessions; plugin actions closing arbitrary tabs; resurrection/session-restore rehydrating clients with stale active tab ids.
Related errors
- Tab index {:?} not found
- No tabs left, cannot move clients: {:?} from closed tab
- Could not find editor pane to replace - is no pane focused?
- failed to find active pane id for client {client_id}
- no active pane for client {client_id}
AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16).
Data as JSON: /api/errors/874ee2aa68d03c50.
Report an issue: GitHub.