{"record":{"id":"17384d6587df7a76","repo":"zellij-org/zellij","slug":"no-tabs-left-cannot-move-clients-from-close","errorCode":null,"errorMessage":"No tabs left, cannot move clients: {:?} from closed tab","messagePattern":"No tabs left, cannot move clients: (.+?) from closed tab","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"zellij-server/src/screen.rs","lineNumber":1820,"sourceCode":"            .find(|t| t.position == position)\n            .map(|t| t.id)\n    }\n\n    /// Gets the display position of the tab with the given ID.\n    ///\n    /// Use this to convert ID → position for user-facing operations.\n    fn get_tab_position_by_id(&self, id: usize) -> Option<usize> {\n        self.tabs.get(&id).map(|t| t.position)\n    }\n\n    fn move_clients_from_closed_tab(\n        &mut self,\n        client_ids_and_mode_infos: Vec<(ClientId, ModeInfo)>,\n    ) -> Result<()> {\n        let err_context = || \"failed to move clients from closed tab\".to_string();\n\n        if self.tabs.is_empty() {\n            Err::<(), _>(anyhow!(\n                \"No tabs left, cannot move clients: {:?} from closed tab\",\n                client_ids_and_mode_infos\n            ))\n            .with_context(err_context)\n            .non_fatal();\n\n            return Ok(());\n        }\n        let first_tab_index = *self\n            .tabs\n            .keys()\n            .next()\n            .context(\"screen contained no tabs\")\n            .with_context(err_context)?;\n        for (client_id, client_mode_info) in client_ids_and_mode_infos {\n            let client_tab_history = self.tab_history.entry(client_id).or_insert_with(Vec::new);\n            if let Some(client_previous_tab) = client_tab_history.pop() {\n                if let Some(client_active_tab) = self.tabs.get_mut(&client_previous_tab) {","sourceCodeStart":1802,"sourceCodeEnd":1838,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-server/src/screen.rs#L1802-L1838","documentation":"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.","triggerScenarios":"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.","commonSituations":"Normal exit-by-last-tab-close, `zellij kill-session`, or kill-all-tabs keybindings; plugin-driven tab closing that removes the last tab.","solutions":["No fix needed — expected during session teardown and explicitly non-fatal","If it fires outside shutdown, check for code paths closing tabs twice (double close events)","Plugin authors: prefer the standard close-tab actions over directly manipulating tab state"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"fn has_remaining_tabs(screen: &Screen) -> bool {\n    !screen.get_tabs().is_empty()\n}","tryCatchPattern":"if self.tabs.is_empty() {\n    // non_fatal log + Ok(()) — session is ending; nothing to relocate\n    return Ok(());\n}","preventionTips":["Treat as expected during last-tab close / session exit","Guard custom flows that close tabs against double-close events"],"tags":["tabs","session","lifecycle","non-fatal","shutdown"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}