{"record":{"id":"a278da51cb743d82","repo":"zellij-org/zellij","slug":"character-key-needs-character-data","errorCode":null,"errorMessage":"Character key needs character data","messagePattern":"Character key needs character data","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"zellij-utils/src/ipc/enum_conversions.rs","lineNumber":79,"sourceCode":"            ProtoBareKey::Right => Ok(BareKey::Right),\n            ProtoBareKey::Home => Ok(BareKey::Home),\n            ProtoBareKey::End => Ok(BareKey::End),\n            ProtoBareKey::Backspace => Ok(BareKey::Backspace),\n            ProtoBareKey::Delete => Ok(BareKey::Delete),\n            ProtoBareKey::Insert => Ok(BareKey::Insert),\n            ProtoBareKey::F1 => Ok(BareKey::F(1)),\n            ProtoBareKey::F2 => Ok(BareKey::F(2)),\n            ProtoBareKey::F3 => Ok(BareKey::F(3)),\n            ProtoBareKey::F4 => Ok(BareKey::F(4)),\n            ProtoBareKey::F5 => Ok(BareKey::F(5)),\n            ProtoBareKey::F6 => Ok(BareKey::F(6)),\n            ProtoBareKey::F7 => Ok(BareKey::F(7)),\n            ProtoBareKey::F8 => Ok(BareKey::F(8)),\n            ProtoBareKey::F9 => Ok(BareKey::F(9)),\n            ProtoBareKey::F10 => Ok(BareKey::F(10)),\n            ProtoBareKey::F11 => Ok(BareKey::F(11)),\n            ProtoBareKey::F12 => Ok(BareKey::F(12)),\n            ProtoBareKey::Char => Err(anyhow!(\"Character key needs character data\")),\n            ProtoBareKey::Tab => Ok(BareKey::Tab),\n            ProtoBareKey::Esc => Ok(BareKey::Esc),\n            ProtoBareKey::Enter => Ok(BareKey::Enter),\n            ProtoBareKey::CapsLock => Ok(BareKey::CapsLock),\n            ProtoBareKey::ScrollLock => Ok(BareKey::ScrollLock),\n            ProtoBareKey::NumLock => Ok(BareKey::NumLock),\n            ProtoBareKey::PrintScreen => Ok(BareKey::PrintScreen),\n            ProtoBareKey::Pause => Ok(BareKey::Pause),\n            ProtoBareKey::Menu => Ok(BareKey::Menu),\n            ProtoBareKey::Unspecified => Err(anyhow!(\"Unspecified bare key\")),\n        }\n    }\n}\n\n// KeyModifier conversions\nimpl From<KeyModifier> for ProtoKeyModifier {\n    fn from(modifier: KeyModifier) -> Self {\n        match modifier {","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/zellij-org/zellij/blob/bf8d23a4f774abf27a108da2a1a2689e7d8d0d23/zellij-utils/src/ipc/enum_conversions.rs#L61-L97","documentation":"Thrown by TryFrom<ProtoBareKey> for BareKey (zellij-utils/src/ipc/enum_conversions.rs): converting the bare enum value ProtoBareKey::Char can never succeed because the actual character is not part of the enum — it lives in the separate `character` field of the enclosing KeyWithModifier message, handled specially in protobuf_conversion.rs (3147-3152 on send, 3179-3192 on receive). Calling the enum-level conversion on a Char is therefore an API misuse.","triggerScenarios":"Calling bare_key_from_proto_i32 (or TryFrom<ProtoBareKey>) with the Char discriminant instead of converting the whole KeyWithModifier message; or a handcrafted IPC frame that sets bare_key=Char but leaves `character` unset, then goes through a path that only converts the enum.","commonSituations":"Custom clients/web clients building key events field-by-field; plugin or test code reusing enum_conversions helpers directly; refactors that bypass the full-message conversion.","solutions":["Convert the complete message: TryFrom<ProtoKeyWithModifier> for KeyWithModifier, which reads the sibling `character` field when bare_key == Char.","When building the proto side, always set `character: Some(c.to_string())` together with bare_key = Char (mirror of the From impl at protobuf_conversion.rs:3148).","If you must reject early, match on the discriminant and treat Char without character data as invalid input at the boundary."],"exampleFix":"// before: enum-only conversion can never produce BareKey::Char\nlet key: BareKey = bare_key_from_proto_i32(proto.bare_key)?; // Err(\"Character key needs character data\")\n\n// after: convert the full message, which carries the character field\nlet key: KeyWithModifier = proto_key.try_into()?; // uses proto.character for Char","handlingStrategy":"type-guard","validationCode":"// sender side: always pair Char with its character\nlet (bare, ch) = match key.bare_key {\n    BareKey::Char(c) => (ProtoBareKey::Char as i32, Some(c.to_string())),\n    other => (bare_key_to_proto_i32(other), None),\n};\nlet msg = ProtoKeyWithModifier { bare_key: bare, key_modifiers: mods, character: ch };","typeGuard":"fn is_fully_specified_key(k: &ProtoKeyWithModifier) -> bool {\n    if k.bare_key == ProtoBareKey::Char as i32 {\n        k.character.as_deref().is_some_and(|s| !s.is_empty())\n    } else {\n        k.bare_key != ProtoBareKey::Unspecified as i32\n    }\n}","tryCatchPattern":"match proto_key.try_into::<KeyWithModifier>() {\n    Ok(key) => Some(key),\n    Err(e) if e.to_string().contains(\"Character key\") => {\n        log::warn!(\"dropping Char key without character data\");\n        None\n    },\n    Err(e) => { log::error!(\"key conversion failed: {e:#}\"); None },\n}","preventionTips":["Never call bare_key_from_proto_i32 on a Char discriminant; convert whole KeyWithModifier messages.","When building protos, set `character` exactly when bare_key == Char (single source of truth in one constructor).","Add round-trip tests (KeyWithModifier -> proto -> KeyWithModifier) so Char handling cannot silently regress."],"tags":["zellij","rust","protobuf","ipc","key-encoding","enum-conversion"],"backgroundTag":"missing-required-proto-field","analyzedSha":"bf8d23a4f774abf27a108da2a1a2689e7d8d0d23","analyzedAt":"2026-08-19T07:42:58.758Z","contentChangedAt":"2026-08-19T07:42:58.758Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}