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

  1. 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
  2. Act on mux notifications (TabClosed/WindowClosed) to invalidate cached tab ids so zoom calls always use current ids
  3. 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

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


AI-assisted analysis of wezterm/wezterm@3ff7522b96 (2026-08-20). Data as JSON: /api/errors/14db1ed4a321093d. Report an issue: GitHub.