{"record":{"id":"5e95fe86de6e1d79","repo":"zellij-org/zellij","slug":"skipconfirm-missing-action","errorCode":null,"errorMessage":"SkipConfirm missing action","messagePattern":"SkipConfirm missing action","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"zellij-utils/src/ipc/protobuf_conversion.rs","lineNumber":2602,"sourceCode":"                })\n            },\n            ActionType::MouseEvent(mouse_event_action) => {\n                Ok(crate::input::actions::Action::MouseEvent {\n                    event: mouse_event_action\n                        .event\n                        .ok_or_else(|| anyhow!(\"MouseEvent missing event\"))?\n                        .try_into()?,\n                })\n            },\n            ActionType::Copy(_) => Ok(crate::input::actions::Action::Copy),\n            ActionType::Confirm(_) => Ok(crate::input::actions::Action::Confirm),\n            ActionType::Deny(_) => Ok(crate::input::actions::Action::Deny),\n            ActionType::SkipConfirm(skip_confirm_action) => {\n                Ok(crate::input::actions::Action::SkipConfirm {\n                    action: Box::new(\n                        skip_confirm_action\n                            .action\n                            .ok_or_else(|| anyhow!(\"SkipConfirm missing action\"))?\n                            .as_ref()\n                            .clone()\n                            .try_into()?,\n                    ),\n                })\n            },\n            ActionType::SearchInput(search_input_action) => {\n                Ok(crate::input::actions::Action::SearchInput {\n                    input: search_input_action\n                        .input\n                        .into_iter()\n                        .map(|b| b as u8)\n                        .collect(),\n                })\n            },\n            ActionType::Search(search_action) => Ok(crate::input::actions::Action::Search {\n                direction: proto_i32_to_search_direction(search_action.direction)?,\n            }),","sourceCodeStart":2584,"sourceCodeEnd":2620,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-utils/src/ipc/protobuf_conversion.rs#L2584-L2620","documentation":"Raised while converting an incoming protobuf IPC Action of type SkipConfirm into zellij's internal Action enum (zellij-utils/ipc/protobuf_conversion.rs). The SkipConfirm message wraps the action that should run without its confirmation prompt; the nested `action` field is a proto3 message field, hence optional on the wire. If a client sends SkipConfirm with the inner action unset, the .ok_or_else() here rejects the conversion and the action is never dispatched.","triggerScenarios":"An IPC client (CLI, plugin, or hand-rolled protobuf sender) emits Action { SkipConfirm {} } with no nested action — e.g. building the protobuf message with all-default fields. The CLI itself always sets it, so this typically comes from custom clients or version-skewed senders using stale generated stubs.","commonSituations":"Scripts/SDKs constructing protobuf actions manually; client built against an older proto schema where SkipConfirm had no inner action; partially-populated payloads after refactors; fuzzing or malformed-message testing.","solutions":["Populate the nested action field: SkipConfirm { action: <some Action> } before sending","Regenerate the client's protobuf stubs from the zellij version the server runs (schema drift is the usual culprit)","Match client and server versions (same zellij release on both sides)","If you control the server loop, log-and-drop the malformed action instead of propagating the error"],"exampleFix":"// before (prost client)\nlet mut a = ProtobufAction::default();\na.action_type = Some(ActionType::SkipConfirm(SkipConfirmAction::default())); // inner action unset\n\n// after\nlet mut inner = ProtobufAction::default();\ninner.action_type = Some(ActionType::Write(WriteAction { characters: \"y\".into() }));\nlet mut a = ProtobufAction::default();\na.action_type = Some(ActionType::SkipConfirm(SkipConfirmAction { action: Some(Box::new(inner)) }));","handlingStrategy":"validation","validationCode":"// before sending SkipConfirm over IPC\nlet Some(skip) = action.action_type.as_ref().and_then(|t| match t {\n    ActionType::SkipConfirm(s) => Some(s),\n    _ => None,\n}) else { /* not this action */ };\nif skip.action.is_none() {\n    anyhow::bail!(\"SkipConfirm requires a nested action\");\n}","typeGuard":"fn skip_confirm_is_valid(s: &SkipConfirmAction) -> bool {\n    s.action.is_some()\n}","tryCatchPattern":"match protobuf_action.try_into() {\n    Ok(action) => dispatch(action),\n    Err(e) if e.to_string().contains(\"SkipConfirm missing action\") => {\n        log::warn!(\"dropping malformed SkipConfirm action from IPC\"); // keep server alive\n    },\n    Err(e) => return Err(e.context(\"action conversion failed\")),\n}","preventionTips":["Never default-construct protobuf actions; always set required submessages explicitly","Generate client stubs from the same zellij commit/version as the server","Add a validation pass over outbound action payloads in test builds","Remember proto3 does not enforce required fields — presence checks are on you"],"tags":["protobuf","ipc","action","skip-confirm","validation"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}