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

SkipConfirm missing action

Error message

SkipConfirm missing action

What it means

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.

Source

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

                })
            },
            ActionType::MouseEvent(mouse_event_action) => {
                Ok(crate::input::actions::Action::MouseEvent {
                    event: mouse_event_action
                        .event
                        .ok_or_else(|| anyhow!("MouseEvent missing event"))?
                        .try_into()?,
                })
            },
            ActionType::Copy(_) => Ok(crate::input::actions::Action::Copy),
            ActionType::Confirm(_) => Ok(crate::input::actions::Action::Confirm),
            ActionType::Deny(_) => Ok(crate::input::actions::Action::Deny),
            ActionType::SkipConfirm(skip_confirm_action) => {
                Ok(crate::input::actions::Action::SkipConfirm {
                    action: Box::new(
                        skip_confirm_action
                            .action
                            .ok_or_else(|| anyhow!("SkipConfirm missing action"))?
                            .as_ref()
                            .clone()
                            .try_into()?,
                    ),
                })
            },
            ActionType::SearchInput(search_input_action) => {
                Ok(crate::input::actions::Action::SearchInput {
                    input: search_input_action
                        .input
                        .into_iter()
                        .map(|b| b as u8)
                        .collect(),
                })
            },
            ActionType::Search(search_action) => Ok(crate::input::actions::Action::Search {
                direction: proto_i32_to_search_direction(search_action.direction)?,
            }),

View on GitHub (pinned to 98a0837077)

Solutions

  1. Populate the nested action field: SkipConfirm { action: <some Action> } before sending
  2. Regenerate the client's protobuf stubs from the zellij version the server runs (schema drift is the usual culprit)
  3. Match client and server versions (same zellij release on both sides)
  4. If you control the server loop, log-and-drop the malformed action instead of propagating the error

Example fix

// before (prost client)
let mut a = ProtobufAction::default();
a.action_type = Some(ActionType::SkipConfirm(SkipConfirmAction::default())); // inner action unset

// after
let mut inner = ProtobufAction::default();
inner.action_type = Some(ActionType::Write(WriteAction { characters: "y".into() }));
let mut a = ProtobufAction::default();
a.action_type = Some(ActionType::SkipConfirm(SkipConfirmAction { action: Some(Box::new(inner)) }));
Defensive patterns

Strategy: validation

Validate before calling

// before sending SkipConfirm over IPC
let Some(skip) = action.action_type.as_ref().and_then(|t| match t {
    ActionType::SkipConfirm(s) => Some(s),
    _ => None,
}) else { /* not this action */ };
if skip.action.is_none() {
    anyhow::bail!("SkipConfirm requires a nested action");
}

Type guard

fn skip_confirm_is_valid(s: &SkipConfirmAction) -> bool {
    s.action.is_some()
}

Try / catch

match protobuf_action.try_into() {
    Ok(action) => dispatch(action),
    Err(e) if e.to_string().contains("SkipConfirm missing action") => {
        log::warn!("dropping malformed SkipConfirm action from IPC"); // keep server alive
    },
    Err(e) => return Err(e.context("action conversion failed")),
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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