{"record":{"id":"36e03544cc255131","repo":"zellij-org/zellij","slug":"halfpagescrolldownbypaneid-missing-pane-id","errorCode":null,"errorMessage":"HalfPageScrollDownByPaneId missing pane_id","messagePattern":"HalfPageScrollDownByPaneId missing pane_id","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"zellij-utils/src/ipc/protobuf_conversion.rs","lineNumber":2970,"sourceCode":"                    pane_id: a\n                        .pane_id\n                        .ok_or_else(|| anyhow!(\"PageScrollDownByPaneId missing pane_id\"))?\n                        .try_into()?,\n                })\n            },\n            ActionType::HalfPageScrollUpByPaneId(a) => {\n                Ok(crate::input::actions::Action::HalfPageScrollUpByPaneId {\n                    pane_id: a\n                        .pane_id\n                        .ok_or_else(|| anyhow!(\"HalfPageScrollUpByPaneId missing pane_id\"))?\n                        .try_into()?,\n                })\n            },\n            ActionType::HalfPageScrollDownByPaneId(a) => {\n                Ok(crate::input::actions::Action::HalfPageScrollDownByPaneId {\n                    pane_id: a\n                        .pane_id\n                        .ok_or_else(|| anyhow!(\"HalfPageScrollDownByPaneId missing pane_id\"))?\n                        .try_into()?,\n                })\n            },\n            ActionType::ResizeByPaneId(a) => {\n                let resize_action = a\n                    .resize_action\n                    .ok_or_else(|| anyhow!(\"ResizeByPaneId missing resize_action\"))?;\n                let resize = proto_i32_to_resize(resize_action.resize)?;\n                let direction = resize_action\n                    .direction\n                    .map(|d| proto_i32_to_direction(d))\n                    .transpose()?;\n                Ok(crate::input::actions::Action::ResizeByPaneId {\n                    pane_id: a\n                        .pane_id\n                        .ok_or_else(|| anyhow!(\"ResizeByPaneId missing pane_id\"))?\n                        .try_into()?,\n                    resize,","sourceCodeStart":2952,"sourceCodeEnd":2988,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-utils/src/ipc/protobuf_conversion.rs#L2952-L2988","documentation":"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'.","triggerScenarios":"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.","commonSituations":"Programmatic action injection from plugins or scripts; version mismatch between the sending client and receiving server; meaning to use the focused-pane HalfPageScrollDown variant.","solutions":["Set pane_id to Some(PaneId { pane_type: Some(PaneType::Terminal(id)) }) before dispatching.","Use HalfPageScrollDown for the focused pane when you have no concrete pane id.","Pin client and server to the same zellij version so the generated contracts match.","Log rejected actions on the server to trace which sender produces incomplete messages."],"exampleFix":"// before\nlet action = ActionType::HalfPageScrollDownByPaneId(HalfPageScrollDownByPaneIdAction {\n    pane_id: None, // -> \"HalfPageScrollDownByPaneId missing pane_id\"\n});\n\n// after\nlet action = ActionType::HalfPageScrollDownByPaneId(HalfPageScrollDownByPaneIdAction {\n    pane_id: Some(PaneId {\n        pane_type: Some(PaneType::Terminal(0)),\n    }),\n});","handlingStrategy":"validation","validationCode":"fn is_sendable(a: &HalfPageScrollDownByPaneIdAction) -> bool {\n    a.pane_id\n        .as_ref()\n        .and_then(|p| p.pane_type.as_ref())\n        .is_some()\n}","typeGuard":"fn has_valid_pane_id(a: &HalfPageScrollDownByPaneIdAction) -> bool {\n    matches!(\n        a.pane_id.as_ref().and_then(|p| p.pane_type.as_ref()),\n        Some(pane_id::PaneType::Terminal(_)) | Some(pane_id::PaneType::Plugin(_))\n    )\n}","tryCatchPattern":"match Action::try_from(proto_action) {\n    Ok(action) => dispatch(action),\n    Err(e) if e.to_string().contains(\"missing pane_id\") => {\n        log::warn!(\"dropping malformed scroll action: {e}\");\n    },\n    Err(e) => return Err(e),\n}","preventionTips":["Treat prost Option fields as required inputs at your API boundary.","Log both the action variant and missing field name when rejecting a message.","Add schema-compat assertions when client and server versions differ."],"tags":["zellij","ipc","protobuf","rust","pane-id","scroll"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}