zellij-org/zellij · error · anyhow::Error

HalfPageScrollDownByPaneId missing pane_id

Error message

HalfPageScrollDownByPaneId missing pane_id

What it means

Zellij converts incoming protobuf IPC actions into its internal Action enum via TryFrom. The HalfPageScrollDownByPaneId variant scrolls a specific pane down by half a page, so HalfPageScrollDownByPaneIdAction must carry the optional pane_id field (PaneId oneof: Terminal(u32) or Plugin(u32)). A message selecting this variant with pane_id unset fails conversion with 'HalfPageScrollDownByPaneId missing pane_id'.

Source

Thrown at zellij-utils/src/ipc/protobuf_conversion.rs:2970

                    pane_id: a
                        .pane_id
                        .ok_or_else(|| anyhow!("PageScrollDownByPaneId missing pane_id"))?
                        .try_into()?,
                })
            },
            ActionType::HalfPageScrollUpByPaneId(a) => {
                Ok(crate::input::actions::Action::HalfPageScrollUpByPaneId {
                    pane_id: a
                        .pane_id
                        .ok_or_else(|| anyhow!("HalfPageScrollUpByPaneId missing pane_id"))?
                        .try_into()?,
                })
            },
            ActionType::HalfPageScrollDownByPaneId(a) => {
                Ok(crate::input::actions::Action::HalfPageScrollDownByPaneId {
                    pane_id: a
                        .pane_id
                        .ok_or_else(|| anyhow!("HalfPageScrollDownByPaneId missing pane_id"))?
                        .try_into()?,
                })
            },
            ActionType::ResizeByPaneId(a) => {
                let resize_action = a
                    .resize_action
                    .ok_or_else(|| anyhow!("ResizeByPaneId missing resize_action"))?;
                let resize = proto_i32_to_resize(resize_action.resize)?;
                let direction = resize_action
                    .direction
                    .map(|d| proto_i32_to_direction(d))
                    .transpose()?;
                Ok(crate::input::actions::Action::ResizeByPaneId {
                    pane_id: a
                        .pane_id
                        .ok_or_else(|| anyhow!("ResizeByPaneId missing pane_id"))?
                        .try_into()?,
                    resize,

View on GitHub (pinned to 98a0837077)

Solutions

  1. Set pane_id to Some(PaneId { pane_type: Some(PaneType::Terminal(id)) }) before dispatching.
  2. Use HalfPageScrollDown for the focused pane when you have no concrete pane id.
  3. Pin client and server to the same zellij version so the generated contracts match.
  4. Log rejected actions on the server to trace which sender produces incomplete messages.

Example fix

// before
let action = ActionType::HalfPageScrollDownByPaneId(HalfPageScrollDownByPaneIdAction {
    pane_id: None, // -> "HalfPageScrollDownByPaneId missing pane_id"
});

// after
let action = ActionType::HalfPageScrollDownByPaneId(HalfPageScrollDownByPaneIdAction {
    pane_id: Some(PaneId {
        pane_type: Some(PaneType::Terminal(0)),
    }),
});
Defensive patterns

Strategy: validation

Validate before calling

fn is_sendable(a: &HalfPageScrollDownByPaneIdAction) -> bool {
    a.pane_id
        .as_ref()
        .and_then(|p| p.pane_type.as_ref())
        .is_some()
}

Type guard

fn has_valid_pane_id(a: &HalfPageScrollDownByPaneIdAction) -> 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("missing pane_id") => {
        log::warn!("dropping malformed scroll action: {e}");
    },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: An action message with action_type = HalfPageScrollDownByPaneId and HalfPageScrollDownByPaneIdAction.pane_id = None, e.g. from a prost struct built via default() or a client whose schema never set the field.

Common situations: Programmatic action injection from plugins or scripts; version mismatch between the sending client and receiving server; meaning to use the focused-pane HalfPageScrollDown variant.

Related errors


AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16). Data as JSON: /api/errors/36e03544cc255131. Report an issue: GitHub.