zellij-org/zellij · warning · anyhow::Error

No tabs left, cannot move clients: {:?} from closed tab

Error message

No tabs left, cannot move clients: {:?} from closed tab

What it means

move_clients_from_closed_tab relocates clients off a just-closed tab onto the first remaining tab. When self.tabs is empty (the closed tab was the last one), there is nowhere to move them; zellij logs this non-fatal error and returns Ok(()) — the session is ending anyway.

Source

Thrown at zellij-server/src/screen.rs:1820

            .find(|t| t.position == position)
            .map(|t| t.id)
    }

    /// Gets the display position of the tab with the given ID.
    ///
    /// Use this to convert ID → position for user-facing operations.
    fn get_tab_position_by_id(&self, id: usize) -> Option<usize> {
        self.tabs.get(&id).map(|t| t.position)
    }

    fn move_clients_from_closed_tab(
        &mut self,
        client_ids_and_mode_infos: Vec<(ClientId, ModeInfo)>,
    ) -> Result<()> {
        let err_context = || "failed to move clients from closed tab".to_string();

        if self.tabs.is_empty() {
            Err::<(), _>(anyhow!(
                "No tabs left, cannot move clients: {:?} from closed tab",
                client_ids_and_mode_infos
            ))
            .with_context(err_context)
            .non_fatal();

            return Ok(());
        }
        let first_tab_index = *self
            .tabs
            .keys()
            .next()
            .context("screen contained no tabs")
            .with_context(err_context)?;
        for (client_id, client_mode_info) in client_ids_and_mode_infos {
            let client_tab_history = self.tab_history.entry(client_id).or_insert_with(Vec::new);
            if let Some(client_previous_tab) = client_tab_history.pop() {
                if let Some(client_active_tab) = self.tabs.get_mut(&client_previous_tab) {

View on GitHub (pinned to 98a0837077)

Solutions

  1. No fix needed — expected during session teardown and explicitly non-fatal
  2. If it fires outside shutdown, check for code paths closing tabs twice (double close events)
  3. Plugin authors: prefer the standard close-tab actions over directly manipulating tab state
Defensive patterns

Strategy: fallback

Type guard

fn has_remaining_tabs(screen: &Screen) -> bool {
    !screen.get_tabs().is_empty()
}

Try / catch

if self.tabs.is_empty() {
    // non_fatal log + Ok(()) — session is ending; nothing to relocate
    return Ok(());
}

Prevention

When it happens

Trigger: Closing the final tab of a session (all clients disconnect) while clients still hold ModeInfo for that tab; races where tab bookkeeping empties before client state is drained.

Common situations: Normal exit-by-last-tab-close, `zellij kill-session`, or kill-all-tabs keybindings; plugin-driven tab closing that removes the last tab.

Related errors


AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16). Data as JSON: /api/errors/17384d6587df7a76. Report an issue: GitHub.