wezterm/wezterm · error
Invalid tab id {}
Error message
Invalid tab id {} What it means
TmuxDomainState::split_pane() (tmux_commands.rs:233) resolves a completed remote split into a local pane. First it looks up the local Tab by TabId in the Mux; when mux.get_tab(tab_id) returns None this bail fires. The Tab was removed — the tmux window was closed, the local window containing it was killed, or the mux is shutting down — while a split request for it was still in flight.
Source
Thrown at mux/src/tmux_commands.rs:243
Box::new(child),
Box::new(pane_pty),
Box::new(writer),
self.domain_id,
"tmux pane".to_string(),
)))
}
pub fn split_pane(
&self,
tab_id: TabId,
pane_id: PaneId,
remote_id: TmuxPaneId,
split_request: SplitRequest,
) -> anyhow::Result<Arc<dyn Pane>> {
let mux = Mux::get();
let tab = match mux.get_tab(tab_id) {
Some(t) => t,
None => anyhow::bail!("Invalid tab id {}", tab_id),
};
let pane_index = match tab
.iter_panes_ignoring_zoom()
.iter()
.find(|p| p.pane.pane_id() == pane_id)
{
Some(p) => p.index,
None => anyhow::bail!("invalid pane id {}", pane_id),
};
let split_size = match tab.compute_split_size(pane_index, split_request) {
Some(s) => s,
None => anyhow::bail!("invalid pane index {}", pane_index),
};
let window_id = match self.gui_tabs.lock().iter().find(|t| t.1.tab_id == tab_id) {
Some((_, tab)) => tab.tmux_window_id,View on GitHub (pinned to 9c04f79f86)
Solutions
- Check mux.get_tab(tab_id).is_some() before resolving the pending split; drop the split if the tab is gone
- Abort pending_splits promises when a tab is removed so stale resolutions never run
- On this error, discard the remote pane id (the tmux pane will be pruned by the next ListAllPanes sync)
Example fix
// before
let tab = match mux.get_tab(tab_id) {
Some(t) => t,
None => anyhow::bail!("Invalid tab id {}", tab_id),
};
// after
let Some(tab) = mux.get_tab(tab_id) else {
log::debug!("tab {tab_id} gone; dropping split for pane {pane_id}");
return Ok(None); // caller skips pane creation
}; Defensive patterns
Strategy: validation
Validate before calling
// Before resolving a pending split:
if mux.get_tab(tab_id).is_none() {
// tab closed while split was in flight; drop the split
return Ok(None);
} Type guard
fn tab_alive(mux: &Mux, tab_id: TabId) -> bool {
mux.get_tab(tab_id).is_some()
} Try / catch
match state.split_pane(tab_id, pane_id, remote_id, req) {
Ok(pane) => Some(pane),
Err(e) if e.to_string().starts_with("Invalid tab id") => {
None // stale split: let next ListAllPanes prune the remote pane
}
Err(e) => return Err(e),
} Prevention
- Cancel pending_splits promises when their tab is removed (mux.remove_tab) so stale resolutions never fire
- Capture tab_id at request time and re-validate at resolution time — assume tabs can die between
- Treat stale-id errors during split resolution as droppable, not fatal
When it happens
Trigger: A pending split promise resolving (WindowPaneChanged) after the user closed the window/tab in wezterm; mux.remove_tab running between the split request (Domain::split_pane captured tab_id) and the split_pane resolution call; GUI shutdown dropping tabs mid-operation.
Common situations: Closing a tmux-attached wezterm window immediately after issuing a split; rapid create/split/close sequences during scripting or UI automation.
Related errors
- No tab {}
- Could not find the tmux pane peer for local pane: {pane_id}
- Split_pane failed
- invalid pane id {}
- invalid pane index {}
AI-assisted analysis of wezterm/wezterm@9c04f79f86 (2026-08-16).
Data as JSON: /api/errors/0923172d5d27cb31.
Report an issue: GitHub.