{"record":{"id":"a46e4756e2dfdff5","repo":"zellij-org/zellij","slug":"failed-to-find-pane-with-id-pane-id","errorCode":null,"errorMessage":"failed to find pane with id {pane_id:?}","messagePattern":"failed to find pane with id (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"zellij-server/src/tab/mod.rs","lineNumber":4405,"sourceCode":"        key_with_modifier: &Option<KeyWithModifier>,\n        raw_input_bytes: Vec<u8>,\n        raw_input_bytes_are_kitty: bool,\n        pane_id: PaneId,\n        client_id: Option<ClientId>,\n        completion_tx: Option<NotificationEnd>,\n    ) -> Result<bool> {\n        // returns true if we need to update the UI (eg. when a command pane is closed with ctrl-c)\n        let err_context = || format!(\"failed to write to pane with id {pane_id:?}\");\n\n        let mut should_update_ui = false;\n        let is_sync_panes_active = self.is_sync_panes_active();\n\n        let active_pane = self\n            .floating_panes\n            .get_mut(&pane_id)\n            .or_else(|| self.tiled_panes.get_pane_mut(pane_id))\n            .or_else(|| self.suppressed_panes.get_mut(&pane_id).map(|p| &mut p.1))\n            .ok_or_else(|| anyhow!(format!(\"failed to find pane with id {pane_id:?}\")))\n            .with_context(err_context)?;\n\n        // We always write for non-synced terminals.\n        // However if the terminal is part of a tab-sync, we need to\n        // check if the terminal should receive input or not (depending on its\n        // 'exclude_from_sync' configuration).\n        let should_not_write_to_terminal = is_sync_panes_active && active_pane.exclude_from_sync();\n\n        if should_not_write_to_terminal {\n            return Ok(should_update_ui);\n        }\n\n        match pane_id {\n            PaneId::Terminal(active_terminal_id) => {\n                match active_pane.adjust_input_to_terminal(\n                    key_with_modifier,\n                    raw_input_bytes,\n                    raw_input_bytes_are_kitty,","sourceCodeStart":4387,"sourceCodeEnd":4423,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-server/src/tab/mod.rs#L4387-L4423","documentation":"Returned by Tab::write_to_pane_id when the target pane id is absent from all three registries searched: floating panes, tiled panes, and the suppressed-panes map. The write to that specific pane is aborted; this usually means the pane was closed between the moment the caller resolved its id and the moment the write executed.","triggerScenarios":"write_to_pane_id invoked with a pane id captured earlier (input routing to a specific pane, sync-panes broadcast, completion notifications) after that pane exited, was closed, or its id was never valid in this tab. Sync-pane mode multiplies exposure since one keypress fans out to many pane ids.","commonSituations":"Sync-panes mode writing to panes that exit mid-session; mouse events routed to a pane that just closed; queued actions referencing dead pids; session resurrection replaying input against stale pane ids; plugins dispatching input by cached PaneId.","solutions":["Re-resolve the pane id from live state immediately before writing instead of caching it","If using sync-panes, expect and tolerate per-pane write failures when some synced panes exit; reopen panes as needed","For queued/async actions, validate the id with tab.get_pane_with_id (or equivalent) right before dispatch","Upgrade zellij - races between input routing and pane exit have seen fixes; check CHANGELOG.md"],"exampleFix":"// before\nlet active_pane = self.floating_panes.get_mut(&pane_id)\n    .or_else(|| self.tiled_panes.get_pane_mut(pane_id))\n    .or_else(|| self.suppressed_panes.get_mut(&pane_id).map(|p| &mut p.1))\n    .ok_or_else(|| anyhow!(format!(\"failed to find pane with id {pane_id:?}\")))\n    .with_context(err_context)?;\n\n// caller-side: validate before dispatching queued input\nif tab.get_pane_with_id(pane_id).is_none() {\n    log::debug!(\"dropping write to dead pane {pane_id:?}\");\n    return Ok(should_update_ui);\n}","handlingStrategy":"validation","validationCode":"// re-validate the pane id at dispatch time, not when it was captured\nif tab.get_pane_with_id(pane_id).is_none() {\n    log::debug!(\"pane {pane_id:?} gone; dropping write\");\n    return Ok(false);\n}","typeGuard":"fn pane_accepts_input(tab: &Tab, pane_id: PaneId) -> bool {\n    tab.get_pane_with_id(pane_id).is_some()\n}","tryCatchPattern":"// sync-panes fan-out must tolerate per-pane failure:\nfor pane_id in target_pane_ids {\n    if let Err(e) = tab.write_to_pane_id(&key, bytes, false, pane_id, Some(client_id), None) {\n        log::debug!(\"write to {pane_id:?} skipped: {e:#}\");\n    }\n}","preventionTips":["Never reuse PaneId values captured before an await/event boundary","In sync-panes mode, expect writes to dead panes and treat them as no-ops","Re-resolve ids from the tab immediately before each write"],"tags":["rust","zellij","input-routing","pane-lifecycle","stale-id","sync-panes"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}