zellij-org/zellij · error
Character key needs character data
Error message
Character key needs character data
What it means
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.
Source
Thrown at zellij-utils/src/ipc/enum_conversions.rs:79
ProtoBareKey::Right => Ok(BareKey::Right),
ProtoBareKey::Home => Ok(BareKey::Home),
ProtoBareKey::End => Ok(BareKey::End),
ProtoBareKey::Backspace => Ok(BareKey::Backspace),
ProtoBareKey::Delete => Ok(BareKey::Delete),
ProtoBareKey::Insert => Ok(BareKey::Insert),
ProtoBareKey::F1 => Ok(BareKey::F(1)),
ProtoBareKey::F2 => Ok(BareKey::F(2)),
ProtoBareKey::F3 => Ok(BareKey::F(3)),
ProtoBareKey::F4 => Ok(BareKey::F(4)),
ProtoBareKey::F5 => Ok(BareKey::F(5)),
ProtoBareKey::F6 => Ok(BareKey::F(6)),
ProtoBareKey::F7 => Ok(BareKey::F(7)),
ProtoBareKey::F8 => Ok(BareKey::F(8)),
ProtoBareKey::F9 => Ok(BareKey::F(9)),
ProtoBareKey::F10 => Ok(BareKey::F(10)),
ProtoBareKey::F11 => Ok(BareKey::F(11)),
ProtoBareKey::F12 => Ok(BareKey::F(12)),
ProtoBareKey::Char => Err(anyhow!("Character key needs character data")),
ProtoBareKey::Tab => Ok(BareKey::Tab),
ProtoBareKey::Esc => Ok(BareKey::Esc),
ProtoBareKey::Enter => Ok(BareKey::Enter),
ProtoBareKey::CapsLock => Ok(BareKey::CapsLock),
ProtoBareKey::ScrollLock => Ok(BareKey::ScrollLock),
ProtoBareKey::NumLock => Ok(BareKey::NumLock),
ProtoBareKey::PrintScreen => Ok(BareKey::PrintScreen),
ProtoBareKey::Pause => Ok(BareKey::Pause),
ProtoBareKey::Menu => Ok(BareKey::Menu),
ProtoBareKey::Unspecified => Err(anyhow!("Unspecified bare key")),
}
}
}
// KeyModifier conversions
impl From<KeyModifier> for ProtoKeyModifier {
fn from(modifier: KeyModifier) -> Self {
match modifier {View on GitHub (pinned to bf8d23a4f7)
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.
Example fix
// before: enum-only conversion can never produce BareKey::Char
let key: BareKey = bare_key_from_proto_i32(proto.bare_key)?; // Err("Character key needs character data")
// after: convert the full message, which carries the character field
let key: KeyWithModifier = proto_key.try_into()?; // uses proto.character for Char Defensive patterns
Strategy: type-guard
Validate before calling
// sender side: always pair Char with its character
let (bare, ch) = match key.bare_key {
BareKey::Char(c) => (ProtoBareKey::Char as i32, Some(c.to_string())),
other => (bare_key_to_proto_i32(other), None),
};
let msg = ProtoKeyWithModifier { bare_key: bare, key_modifiers: mods, character: ch }; Type guard
fn is_fully_specified_key(k: &ProtoKeyWithModifier) -> bool {
if k.bare_key == ProtoBareKey::Char as i32 {
k.character.as_deref().is_some_and(|s| !s.is_empty())
} else {
k.bare_key != ProtoBareKey::Unspecified as i32
}
} Try / catch
match proto_key.try_into::<KeyWithModifier>() {
Ok(key) => Some(key),
Err(e) if e.to_string().contains("Character key") => {
log::warn!("dropping Char key without character data");
None
},
Err(e) => { log::error!("key conversion failed: {e:#}"); None },
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid BareKey value: {}
- Unspecified bare key
- Invalid KeyModifier value: {}
- Unspecified key modifier
- Missing pixel_dimensions
AI-assisted analysis of zellij-org/zellij@bf8d23a4f7 (2026-08-19).
Data as JSON: /api/errors/a278da51cb743d82.
Report an issue: GitHub.