zellij-org/zellij · error · anyhow::Error
EditScrollbackByPaneId missing pane_id
Error message
EditScrollbackByPaneId missing pane_id
What it means
EditScrollbackByPaneId opens the scrollback of one specific pane in an editor; the internal Action also carries an ansi: bool flag taken straight from the proto field. The protobuf message EditScrollbackByPaneIdAction requires pane_id; ansi alone is not enough. With pane_id = None the conversion fails with 'EditScrollbackByPaneId missing pane_id'.
Source
Thrown at zellij-utils/src/ipc/protobuf_conversion.rs:3022
pane_id: a
.pane_id
.ok_or_else(|| anyhow!("MovePaneBackwardsByPaneId missing pane_id"))?
.try_into()?,
})
},
ActionType::ClearScreenByPaneId(a) => {
Ok(crate::input::actions::Action::ClearScreenByPaneId {
pane_id: a
.pane_id
.ok_or_else(|| anyhow!("ClearScreenByPaneId missing pane_id"))?
.try_into()?,
})
},
ActionType::EditScrollbackByPaneId(a) => {
Ok(crate::input::actions::Action::EditScrollbackByPaneId {
pane_id: a
.pane_id
.ok_or_else(|| anyhow!("EditScrollbackByPaneId missing pane_id"))?
.try_into()?,
ansi: a.ansi,
})
},
ActionType::ToggleFullscreenByPaneId(a) => Ok(
crate::input::actions::Action::ToggleFocusFullscreenByPaneId {
pane_id: a
.pane_id
.ok_or_else(|| anyhow!("ToggleFullscreenByPaneId missing pane_id"))?
.try_into()?,
},
),
ActionType::ToggleNoUiFullscreenByPaneId(a) => Ok(
crate::input::actions::Action::ToggleFocusNoUiFullscreenByPaneId {
pane_id: a
.pane_id
.ok_or_else(|| anyhow!("ToggleNoUiFullscreenByPaneId missing pane_id"))?
.try_into()?,View on GitHub (pinned to 98a0837077)
Solutions
- Resolve a real pane id first and set pane_id: Some(PaneId { pane_type: Some(PaneType::Terminal(id)) }); keep ansi as needed.
- Use the plain EditScrollback action when targeting the focused pane.
- Check that the pane id you resolved actually exists (e.g. via a pane-list query) before sending.
- Rebuild custom clients against the current contract.
Example fix
// before
let action = ActionType::EditScrollbackByPaneId(EditScrollbackByPaneIdAction {
pane_id: None, // -> "EditScrollbackByPaneId missing pane_id"
ansi: true,
});
// after
let action = ActionType::EditScrollbackByPaneId(EditScrollbackByPaneIdAction {
pane_id: Some(PaneId { pane_type: Some(PaneType::Terminal(1)) }),
ansi: true,
}); Defensive patterns
Strategy: validation
Validate before calling
fn is_sendable(a: &EditScrollbackByPaneIdAction) -> bool {
a.pane_id
.as_ref()
.and_then(|p| p.pane_type.as_ref())
.is_some()
} Type guard
fn has_valid_pane_id(a: &EditScrollbackByPaneIdAction) -> bool {
matches!(
a.pane_id.as_ref().and_then(|p| p.pane_type.as_ref()),
Some(pane_id::PaneType::Terminal(_)) | Some(pane_id::PaneType::Plugin(_))
)
} Try / catch
match Action::try_from(proto_action) {
Ok(action) => dispatch(action),
Err(e) if e.to_string().contains("EditScrollbackByPaneId missing pane_id") => {
log::warn!("edit-scrollback action without pane target: {e}");
},
Err(e) => return Err(e),
} Prevention
- ansi is not a substitute for pane_id - both parts of the tuple matter.
- When a pane-id lookup returns None, surface the lookup failure instead of sending the action.
- Pin the zellij-tile/contract crate version to the running server.
When it happens
Trigger: Sending ActionType::EditScrollbackByPaneId where EditScrollbackByPaneIdAction.pane_id is None, regardless of the ansi flag value.
Common situations: Plugins wiring an 'edit scrollback' command to a pane id they failed to resolve; default-constructed prost messages; version skew between sender and receiver; intending the focused-pane EditScrollback variant.
Related errors
- PageScrollUpByPaneId missing pane_id
- PageScrollDownByPaneId missing pane_id
- HalfPageScrollUpByPaneId missing pane_id
- HalfPageScrollDownByPaneId missing pane_id
- ResizeByPaneId missing resize_action
AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16).
Data as JSON: /api/errors/2d7b385c48cd60d6.
Report an issue: GitHub.