{"record":{"id":"3b8b37fd823bf7c6","repo":"wezterm/wezterm","slug":"invalid-pane-id-3b8b37","errorCode":null,"errorMessage":"invalid pane id {}","messagePattern":"invalid pane id (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mux/src/tmux_commands.rs","lineNumber":252,"sourceCode":"        &self,\n        tab_id: TabId,\n        pane_id: PaneId,\n        remote_id: TmuxPaneId,\n        split_request: SplitRequest,\n    ) -> anyhow::Result<Arc<dyn Pane>> {\n        let mux = Mux::get();\n        let tab = match mux.get_tab(tab_id) {\n            Some(t) => t,\n            None => anyhow::bail!(\"Invalid tab id {}\", tab_id),\n        };\n\n        let pane_index = match tab\n            .iter_panes_ignoring_zoom()\n            .iter()\n            .find(|p| p.pane.pane_id() == pane_id)\n        {\n            Some(p) => p.index,\n            None => anyhow::bail!(\"invalid pane id {}\", pane_id),\n        };\n\n        let split_size = match tab.compute_split_size(pane_index, split_request) {\n            Some(s) => s,\n            None => anyhow::bail!(\"invalid pane index {}\", pane_index),\n        };\n\n        let window_id = match self.gui_tabs.lock().iter().find(|t| t.1.tab_id == tab_id) {\n            Some((_, tab)) => tab.tmux_window_id,\n            None => anyhow::bail!(\"No tab {}\", tab_id),\n        };\n\n        let p = PaneItem {\n            session_id: 0,\n            window_id: window_id,\n            pane_id: remote_id,\n            _pane_index: 0,\n            cursor_x: 0,","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/wezterm/wezterm/blob/9c04f79f86649f76a8c978ff4b674f60297a6ec9/mux/src/tmux_commands.rs#L234-L270","documentation":"In TmuxDomainState::split_pane(), after the tab is found, the source pane must be located among the tab's panes via iter_panes_ignoring_zoom() to compute the split geometry. This bail fires when pane_id is not one of that tab's panes: the pane was closed locally in the interim, or the pane belongs to a different tab than the tab_id supplied. The pane id and tab id have become inconsistent.","triggerScenarios":"Resolving a pending split after the source pane was closed (pane exit, window closed) while tab_id stayed valid; calling split_pane with a (tab_id, pane_id) pair captured at different times; a pane pruned by remove_detached_pane between split request and resolution.","commonSituations":"Fast pane churn in tmux (processes exiting with remain-on-exit off); splits racing window resyncs that rebuild tab membership.","solutions":["Validate the pair before resolving: tab.iter_panes_ignoring_zoom().iter().any(|p| p.pane.pane_id() == pane_id)","If stale, drop the split (return no pane) instead of erroring — the next ListAllPanes prune reconciles state","Capture (tab_id, pane_id) atomically from a single mux snapshot when queueing splits"],"exampleFix":"// before\nlet pane_index = match tab.iter_panes_ignoring_zoom().iter().find(|p| p.pane.pane_id() == pane_id) {\n    Some(p) => p.index,\n    None => anyhow::bail!(\"invalid pane id {}\", pane_id),\n};\n\n// after\nlet Some(pane_index) = tab.iter_panes_ignoring_zoom().iter().find(|p| p.pane.pane_id() == pane_id).map(|p| p.index) else {\n    log::debug!(\"pane {pane_id} no longer in tab {tab_id}; dropping split\");\n    return Ok(None);\n};","handlingStrategy":"validation","validationCode":"// Validate the (tab, pane) pair before split resolution:\nlet valid = mux\n    .get_tab(tab_id)\n    .map(|t| t.iter_panes_ignoring_zoom().iter().any(|p| p.pane.pane_id() == pane_id))\n    .unwrap_or(false);\nif !valid {\n    return Ok(None); // pane left the tab; drop the split\n}","typeGuard":"fn pane_in_tab(tab: &Arc<Tab>, pane_id: PaneId) -> bool {\n    tab.iter_panes_ignoring_zoom().iter().any(|p| p.pane.pane_id() == pane_id)\n}","tryCatchPattern":"match state.split_pane(tab_id, pane_id, remote_id, req) {\n    Ok(pane) => Some(pane),\n    Err(e) if e.to_string().starts_with(\"invalid pane id\") => None, // stale; next sync reconciles\n    Err(e) => return Err(e),\n}","preventionTips":["Capture (tab_id, pane_id) atomically from one mux snapshot when queueing splits","Re-validate pair membership at resolution time; panes close independently of tabs","Let the ListAllPanes prune reconcile remote state instead of erroring on stale local ids"],"tags":["rust","wezterm","tmux","split-pane","pane-id","state-sync"],"backgroundTag":"unknown-pane-id","analyzedSha":"9c04f79f86649f76a8c978ff4b674f60297a6ec9","analyzedAt":"2026-08-16T21:23:27.157Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}