wezterm/wezterm · error
fontconfig not compiled in
Error message
fontconfig not compiled in
What it means
The SetPaneZoomed handler's second lookup failed on containing_tab_id — an id supplied by the client in the PDU, not resolved by the server. The client derived it from its cached pane tree (a ListPanes snapshot); if the server-side tab was closed, moved, or renumbered-in-place since that snapshot, get_tab returns None and the server replies "Error: no such tab {containing_tab_id}". This is a client/server cache desync, not a missing pane.
Source
Thrown at wezterm-font/src/locator/mod.rs:228
) -> anyhow::Result<Vec<ParsedFont>>;
fn enumerate_all_fonts(&self) -> anyhow::Result<Vec<ParsedFont>> {
Ok(vec![])
}
fn locate_fallback_for_codepoints(
&self,
codepoints: &[char],
) -> anyhow::Result<Vec<ParsedFont>>;
}
pub fn new_locator(locator: FontLocatorSelection) -> Arc<dyn FontLocator + Send + Sync> {
match locator {
FontLocatorSelection::FontConfig => {
#[cfg(all(unix, not(target_os = "macos")))]
return Arc::new(font_config::FontConfigFontLocator {});
#[cfg(not(all(unix, not(target_os = "macos"))))]
panic!("fontconfig not compiled in");
}
FontLocatorSelection::CoreText => {
#[cfg(target_os = "macos")]
return Arc::new(core_text::CoreTextFontLocator {});
#[cfg(not(target_os = "macos"))]
panic!("CoreText not compiled in");
}
FontLocatorSelection::Gdi => {
#[cfg(windows)]
return Arc::new(gdi::GdiFontLocator {});
#[cfg(not(windows))]
panic!("Gdi not compiled in");
}
FontLocatorSelection::ConfigDirsOnly => Arc::new(NopSystemSource {}),
}
}
struct NopSystemSource {}View on GitHub (pinned to 3ff7522b96)
Solutions
- Re-sync ids from a fresh ListPanes (or `wezterm cli list`) immediately before calling set_zoomed — the PaneEntry rows carry both pane_id and tab_id
- Act on mux notifications (TabClosed/WindowClosed) to invalidate cached tab ids so zoom calls always use current ids
- Treat the error as transient: re-resolve and retry once; if the tab is truly gone, abandon the operation
Example fix
# before: tab id captured earlier in the script wezterm cli ... # uses TAB=5 -> Error: no such tab 5 # after: derive tab id from the live pane at call time TAB=$(wezterm cli list --format json | jq "[.[] | select(.pane_id==$PANE)][0].tab_id") [ -n "$TAB" ] && echo "zoom pane $PANE in tab $TAB"
Defensive patterns
Strategy: validation
Validate before calling
// Re-derive containing_tab_id from a fresh snapshot instead of trusting the cache
let panes = conn.list_panes().await?;
let entry = find_entry(&panes, pane_id)
.ok_or_else(|| anyhow!("pane {pane_id} gone"))?;
conn.set_zoomed(SetPaneZoomed { containing_tab_id: entry.tab_id, pane_id, zoomed }).await?; Type guard
fn tab_alive(res: &ListPanesResponse, tab_id: TabId) -> bool {
fn walk(n: &PaneNode, t: TabId) -> bool {
match n {
PaneNode::Leaf(e) => e.tab_id == t,
PaneNode::Split { left, right, .. } => walk(left, t) || walk(right, t),
PaneNode::Empty => false,
}
}
res.tabs.iter().any(|n| walk(n, tab_id))
} Try / catch
match conn.set_zoomed(SetPaneZoomed { containing_tab_id, pane_id, zoomed }).await {
Ok(r) => r,
Err(e) if e.to_string().contains("no such tab") => {
// client cache desync: re-list, re-pair pane/tab ids, retry once
let fresh = conn.list_panes().await?;
let entry = find_entry(&fresh, pane_id).context("pane also gone")?;
conn.set_zoomed(SetPaneZoomed { containing_tab_id: entry.tab_id, pane_id, zoomed }).await?
}
Err(e) => return Err(e),
} Prevention
- Always pair pane_id and containing_tab_id from the same ListPanes snapshot; never mix snapshots
- Invalidate the cached pane tree on TabClosed/WindowClosed notifications before issuing zoom/resize RPCs
- Treat containing_tab_id as an opaque server-assigned value: never reuse it across a kill-server/restart
When it happens
Trigger: Toggling zoom after another client closed or reorganized the tab; GUI attached to a unix/tls/ssh mux domain lagging behind tab-close notifications; using tab ids from an older `wezterm cli list` while the tab list changed.
Common situations: Multi-client mux domains where tabs are opened/closed concurrently; flaky notification delivery on remote domains; scripts that cache (pane_id, tab_id) pairs across user-visible delays.
Related errors
- unhandled type for {name}: {:#?}
- Gdi not compiled in
- NSPasteboard::generalPasteboard returned null
- TermWizTerminal::waker called!?
- TerminalShim::waker called!?
AI-assisted analysis of wezterm/wezterm@3ff7522b96 (2026-08-20).
Data as JSON: /api/errors/14db1ed4a321093d.
Report an issue: GitHub.