{"record":{"id":"4501a7fd76bfaee0","repo":"zellij-org/zellij","slug":"unknown-component","errorCode":null,"errorMessage":"Unknown component: {}","messagePattern":"Unknown component: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"zellij-server/src/ui/components/mod.rs","lineNumber":124,"sourceCode":"            );\n            parse_vte_bytes!(self, encoded_text);\n            Ok(())\n        } else if component_name == &\"nested_list\" {\n            let nested_list_items = parse_nested_list_items(params_iter);\n            let encoded_nested_list =\n                nested_list(nested_list_items, &self.style, component_coordinates);\n            parse_vte_bytes!(self, encoded_nested_list);\n            Ok(())\n        } else if component_name == &\"text\" {\n            let stringified_params = parse_text_params(params_iter)\n                .into_iter()\n                .next()\n                .with_context(|| format!(\"text must have, well, text...\"))?;\n            let encoded_text = text(stringified_params, &self.style, component_coordinates);\n            parse_vte_bytes!(self, encoded_text);\n            Ok(())\n        } else {\n            Err(anyhow!(\"Unknown component: {}\", component_name))\n        }\n    }\n    fn parse_coordinates(&self, coordinates: &str) -> Result<Option<Coordinates>> {\n        lazy_static! {\n            static ref RE: Regex = Regex::new(r\"(\\d*)/(\\d*)/(\\d*)/(\\d*)\").unwrap();\n        }\n        if let Some(captures) = RE.captures_iter(&coordinates).next() {\n            let x = captures[1].parse::<usize>().with_context(|| {\n                format!(\n                    \"Failed to parse x coordinates for string: {:?}\",\n                    coordinates\n                )\n            })?;\n            let y = captures[2].parse::<usize>().with_context(|| {\n                format!(\n                    \"Failed to parse y coordinates for string: {:?}\",\n                    coordinates\n                )","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-server/src/ui/components/mod.rs#L106-L142","documentation":"UiComponentParser::parse in zellij-server renders UI components from a byte payload decoded to a 'component_name;params...' string. It recognizes exactly four component names — table, ribbon, nested_list, text — and dispatches on the first ';'-separated token; any other first token falls through to this 'Unknown component' error. The parser is the rendering side of the custom UI-component mini-language zellij uses to draw plugin/host UI (tables, ribbons, lists, text) through the ANSI grid.","triggerScenarios":"A component string whose first token is not table/ribbon/nested_list/text: a typo or wrong case ('Text', 'button'), a payload where the component name was never sent (params only), or a component introduced in a newer zellij being rendered by an older binary that does not know the name yet.","commonSituations":"Plugin/zellij version skew after upgrade (new component names on old server); hand-crafted component strings in tests or plugins with case/typo mistakes; payloads where UTF-8 lossy decoding or ';' splitting shifted the name out of position; semicolons inside the name portion.","solutions":["Use one of the four supported component names exactly: table, ribbon, nested_list, text","Align versions: run the plugin against a zellij server of the same or newer release than the plugin was built for","Re-check the payload format: name first, optional x/y/w/h coordinates matching d*/d*/d*/d* next, then params, all ';'-separated","If a genuinely new component is needed, add a matching branch in UiComponentParser::parse rather than sending an unknown name"],"exampleFix":"// before\ncomponent_bytes = format!(\"TextLabel;{}\", my_text).into_bytes();\n\n// after\ncomponent_bytes = format!(\"text;{}\", my_text).into_bytes();","handlingStrategy":"type-guard","validationCode":"const KNOWN_COMPONENTS: [&str; 4] = [\"table\", \"ribbon\", \"nested_list\", \"text\"];\n\nlet first = payload_str.split(';').next().unwrap_or(\"\");\nif !KNOWN_COMPONENTS.contains(&first) {\n    log::warn!(\"skipping unsupported ui component: {first}\");\n    return Ok(());\n}","typeGuard":"fn is_known_component(payload: &[u8]) -> bool {\n    let first = String::from_utf8_lossy(payload)\n        .split(';')\n        .next()\n        .unwrap_or(\"\");\n    matches!(first, \"table\" | \"ribbon\" | \"nested_list\" | \"text\")\n}","tryCatchPattern":"if let Err(e) = parser.parse(component_bytes) {\n    if e.to_string().starts_with(\"Unknown component\") {\n        log::warn!(\"ignoring unknown ui component: {e:#}\"); // forward-compat: skip, don't kill the render\n    } else {\n        return Err(e);\n    }\n}","preventionTips":["Keep component-name vocabulary in one shared constant used by both sender and parser","Version-gate new component names so old servers never receive them","Add a fast allowlist check before invoking UiComponentParser::parse","Never rely on case-insensitivity: matching is exact"],"tags":["ui","components","parsing","plugin-protocol","version-skew"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}