{"record":{"id":"cfcbfa658953ac87","repo":"zellij-org/zellij","slug":"newtiledpluginpane-missing-plugin","errorCode":null,"errorMessage":"NewTiledPluginPane missing plugin","messagePattern":"NewTiledPluginPane missing plugin","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"zellij-utils/src/ipc/protobuf_conversion.rs","lineNumber":2650,"sourceCode":"                Ok(crate::input::actions::Action::OverrideLayout {\n                    tabs: override_layout_action\n                        .tabs\n                        .into_iter()\n                        .map(|t| t.try_into())\n                        .collect::<Result<Vec<_>>>()?,\n                    retain_existing_terminal_panes: override_layout_action\n                        .retain_existing_terminal_panes,\n                    retain_existing_plugin_panes: override_layout_action\n                        .retain_existing_plugin_panes,\n                    apply_only_to_active_tab: override_layout_action.apply_only_to_active_tab,\n                })\n            },\n            ActionType::QueryTabNames(_) => Ok(crate::input::actions::Action::QueryTabNames),\n            ActionType::NewTiledPluginPane(new_tiled_plugin_action) => {\n                Ok(crate::input::actions::Action::NewTiledPluginPane {\n                    plugin: new_tiled_plugin_action\n                        .plugin\n                        .ok_or_else(|| anyhow!(\"NewTiledPluginPane missing plugin\"))?\n                        .try_into()?,\n                    pane_name: new_tiled_plugin_action.pane_name,\n                    skip_cache: new_tiled_plugin_action.skip_cache,\n                    cwd: new_tiled_plugin_action.cwd.map(PathBuf::from),\n                    no_focus: new_tiled_plugin_action.no_focus,\n                    tab_id: new_tiled_plugin_action.tab_id.map(|t| t as usize),\n                })\n            },\n            ActionType::NewFloatingPluginPane(new_floating_plugin_action) => {\n                Ok(crate::input::actions::Action::NewFloatingPluginPane {\n                    plugin: new_floating_plugin_action\n                        .plugin\n                        .ok_or_else(|| anyhow!(\"NewFloatingPluginPane missing plugin\"))?\n                        .try_into()?,\n                    pane_name: new_floating_plugin_action.pane_name,\n                    skip_cache: new_floating_plugin_action.skip_cache,\n                    cwd: new_floating_plugin_action.cwd.map(PathBuf::from),\n                    coordinates: new_floating_plugin_action","sourceCodeStart":2632,"sourceCodeEnd":2668,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-utils/src/ipc/protobuf_conversion.rs#L2632-L2668","documentation":"Conversion of the protobuf IPC action NewTiledPluginPane into the internal Action requires the nested `plugin` message (location + config of the wasm plugin to open as a tiled pane). Because `plugin` is a proto3 message field it is Option on the Rust side; an incoming NewTiledPluginPane without it fails here and the pane is never created.","triggerScenarios":"Sending Action { NewTiledPluginPane { ... } } over IPC with the plugin field unset — default-constructed messages from custom clients, stale generated stubs, or a truncated/malformed payload.","commonSituations":"Automation or plugin frameworks opening plugin panes programmatically without setting the plugin location; client/server built from different zellij versions with schema drift; tests emitting default actions.","solutions":["Set the `plugin` field (at minimum a _location: tag or file path) on NewTiledPluginPane before sending","Regenerate protobuf stubs for the client from the server's zellij version","Align CLI/plugin and server versions","Validate required fields before dispatch and drop malformed actions with a log line"],"exampleFix":"// before\nlet a = ProtobufAction::default();\na.action_type = Some(ActionType::NewTiledPluginPane(NewTiledPluginPaneAction { ..Default::default() })); // plugin: None\n\n// after\nlet a = ProtobufAction::default();\na.action_type = Some(ActionType::NewTiledPluginPane(NewTiledPluginPaneAction {\n    plugin: Some(ProtobufPlugin { _location: Some(location), ..Default::default() }),\n    ..Default::default()\n}));","handlingStrategy":"validation","validationCode":"if let ActionType::NewTiledPluginPane(a) = action.action_type.as_ref().unwrap() {\n    if a.plugin.is_none() {\n        anyhow::bail!(\"NewTiledPluginPane requires a plugin location\");\n    }\n}","typeGuard":"fn new_tiled_plugin_action_is_valid(a: &NewTiledPluginPaneAction) -> bool {\n    a.plugin.as_ref().is_some_and(|p| p._location.is_some())\n}","tryCatchPattern":"match protobuf_action.try_into() {\n    Ok(action) => dispatch(action),\n    Err(e) if e.to_string().contains(\"NewTiledPluginPane missing plugin\") => {\n        log::warn!(\"dropping malformed NewTiledPluginPane action\");\n    },\n    Err(e) => return Err(e.context(\"action conversion failed\")),\n}","preventionTips":["Always attach a plugin location (_location) when building plugin-pane actions","Regenerate stubs when the proto changes; keep client/server versions in lockstep","Unit-test IPC message builders asserting required fields are set","Treat 'missing submessage' conversion errors as sender bugs, not server flakiness"],"tags":["protobuf","ipc","action","plugin","validation"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}