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

NewFloatingPluginPane missing plugin

Error message

NewFloatingPluginPane missing plugin

What it means

Conversion of the protobuf IPC action NewFloatingPluginPane into the internal Action requires the nested `plugin` message (the wasm plugin to open as a floating pane). The field is optional proto3; if unset on the wire the .ok_or_else() here aborts conversion, so the floating plugin pane is never created and the error propagates to the IPC caller.

Source

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

            ActionType::QueryTabNames(_) => Ok(crate::input::actions::Action::QueryTabNames),
            ActionType::NewTiledPluginPane(new_tiled_plugin_action) => {
                Ok(crate::input::actions::Action::NewTiledPluginPane {
                    plugin: new_tiled_plugin_action
                        .plugin
                        .ok_or_else(|| anyhow!("NewTiledPluginPane missing plugin"))?
                        .try_into()?,
                    pane_name: new_tiled_plugin_action.pane_name,
                    skip_cache: new_tiled_plugin_action.skip_cache,
                    cwd: new_tiled_plugin_action.cwd.map(PathBuf::from),
                    no_focus: new_tiled_plugin_action.no_focus,
                    tab_id: new_tiled_plugin_action.tab_id.map(|t| t as usize),
                })
            },
            ActionType::NewFloatingPluginPane(new_floating_plugin_action) => {
                Ok(crate::input::actions::Action::NewFloatingPluginPane {
                    plugin: new_floating_plugin_action
                        .plugin
                        .ok_or_else(|| anyhow!("NewFloatingPluginPane missing plugin"))?
                        .try_into()?,
                    pane_name: new_floating_plugin_action.pane_name,
                    skip_cache: new_floating_plugin_action.skip_cache,
                    cwd: new_floating_plugin_action.cwd.map(PathBuf::from),
                    coordinates: new_floating_plugin_action
                        .coordinates
                        .map(|c| c.try_into())
                        .transpose()?,
                    no_focus: new_floating_plugin_action.no_focus,
                    tab_id: new_floating_plugin_action.tab_id.map(|t| t as usize),
                })
            },
            ActionType::NewInPlacePluginPane(new_in_place_plugin_action) => {
                Ok(crate::input::actions::Action::NewInPlacePluginPane {
                    plugin: new_in_place_plugin_action
                        .plugin
                        .ok_or_else(|| anyhow!("NewInPlacePluginPane missing plugin"))?
                        .try_into()?,

View on GitHub (pinned to 98a0837077)

Solutions

  1. Always populate the `plugin` field with a valid location when sending NewFloatingPluginPane
  2. Regenerate the client's protobuf code against the server's proto files
  3. Pin client and server to the same zellij release
  4. Add a pre-send validation step rejecting actions whose required submessages are missing

Example fix

// before
NewFloatingPluginPaneAction { pane_name: Some("notes".into()), ..Default::default() } // plugin: None -> error

// after
NewFloatingPluginPaneAction {
    plugin: Some(ProtobufPlugin { _location: Some(protobu_f_plugin_location("zellij:notes")), ..Default::default() }),
    pane_name: Some("notes".into()),
    ..Default::default()
}
Defensive patterns

Strategy: validation

Validate before calling

if let ActionType::NewFloatingPluginPane(a) = action.action_type.as_ref().unwrap() {
    if a.plugin.is_none() {
        anyhow::bail!("NewFloatingPluginPane requires a plugin location");
    }
}

Type guard

fn new_floating_plugin_action_is_valid(a: &NewFloatingPluginPaneAction) -> bool {
    a.plugin.is_some()
}

Try / catch

match protobuf_action.try_into() {
    Ok(action) => dispatch(action),
    Err(e) if e.to_string().contains("NewFloatingPluginPane missing plugin") => {
        log::warn!("dropping malformed NewFloatingPluginPane action");
    },
    Err(e) => return Err(e.context("action conversion failed")),
}

Prevention

When it happens

Trigger: An IPC sender emits NewFloatingPluginPane with all-default fields (plugin: None), or with only optional fields like pane_name/cwd set — from custom clients, old stubs, or malformed payloads.

Common situations: Programmatic creation of floating plugin panes from scripts/plugins that forget the plugin location; client-server version mismatch after the action gained fields; partial serialization bugs.

Related errors


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