zellij-org/zellij · error · anyhow::Error
Character key missing character data
Error message
Character key missing character data
What it means
When converting a protobuf KeyWithModifier to zellij's data::Key, the special case bare_key == BareKey::Char means the actual character must arrive in the separate optional string field character (proto comment: 'Only set when bare_key is CHAR'). If the discriminator says Char but character is None, the conversion fails with 'Character key missing character data'. The proto enum has Unspecified = 0, so this is not a default-value trap - the sender explicitly chose Char without the payload.
Source
Thrown at zellij-utils/src/ipc/protobuf_conversion.rs:3161
}
impl TryFrom<crate::client_server_contract::client_server_contract::KeyWithModifier>
for crate::data::KeyWithModifier
{
type Error = anyhow::Error;
fn try_from(
key: crate::client_server_contract::client_server_contract::KeyWithModifier,
) -> Result<Self> {
use crate::ipc::enum_conversions::{bare_key_from_proto_i32, key_modifier_from_proto_i32};
use std::collections::BTreeSet;
// Handle character keys specially
let bare_key = if key.bare_key
== crate::client_server_contract::client_server_contract::BareKey::Char as i32
{
let character_str = key
.character
.ok_or_else(|| anyhow!("Character key missing character data"))?;
let character = character_str
.chars()
.next()
.ok_or_else(|| anyhow!("Empty character string"))?;
crate::data::BareKey::Char(character)
} else {
bare_key_from_proto_i32(key.bare_key)?
};
let key_modifiers: Result<BTreeSet<_>> = key
.key_modifiers
.into_iter()
.map(|modifier| key_modifier_from_proto_i32(modifier))
.collect();
Ok(Self {
bare_key,
key_modifiers: key_modifiers?,View on GitHub (pinned to 98a0837077)
Solutions
- Always pair bare_key = BareKey::Char with character: Some("a".to_string()) containing the character.
- If the key is not a printable character, send the matching named BareKey variant (Enter, Tab, Esc, ...) instead of Char.
- Write a round-trip test data::Key -> KeyWithModifier -> data::Key over your key set.
- Rebuild senders against the current contract so the character field exists.
Example fix
// before
let key = KeyWithModifier {
bare_key: BareKey::Char as i32,
key_modifiers: vec![KeyModifier::Ctrl as i32],
character: None, // -> "Character key missing character data"
};
// after
let key = KeyWithModifier {
bare_key: BareKey::Char as i32,
key_modifiers: vec![KeyModifier::Ctrl as i32],
character: Some("c".to_string()),
}; Defensive patterns
Strategy: validation
Validate before calling
fn key_is_convertible(k: &KeyWithModifier) -> bool {
if k.bare_key == BareKey::Char as i32 {
matches!(k.character.as_deref(), Some(s) if !s.is_empty())
} else {
true // named keys validated by bare_key_from_proto_i32
}
} Type guard
fn is_valid_char_key(k: &KeyWithModifier) -> bool {
k.bare_key != BareKey::Char as i32
|| k.character
.as_deref()
.map(|s| s.chars().next().is_some())
.unwrap_or(false)
} Try / catch
match zellij_utils::data::Key::try_from(proto_key) {
Ok(key) => handle_key(key),
Err(e) if e.to_string().contains("Character key missing character data") => {
log::warn!("dropping Char key without character payload");
},
Err(e) => return Err(e),
} Prevention
- Treat bare_key = Char and the character string as an inseparable pair when serializing key events.
- Only set bare_key = Char for printable characters; use named BareKey variants otherwise.
- Round-trip test your full keymap through the proto layer.
When it happens
Trigger: Sending a KeyWithModifier over IPC with bare_key = BareKey::Char as i32 but character unset, e.g. serializing a key event and dropping the character string, or a keymap tool that encodes every printable key as Char without attaching the char.
Common situations: Custom input pipelines or remote/protocol clients forwarding key events into zellij; plugins synthesizing key events; version skew where an older sender's KeyWithModifier had no character field.
Related errors
- Empty character string
- PageScrollUpByPaneId missing pane_id
- PageScrollDownByPaneId missing pane_id
- HalfPageScrollUpByPaneId missing pane_id
- HalfPageScrollDownByPaneId missing pane_id
AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16).
Data as JSON: /api/errors/cc8e055ba5fa43be.
Report an issue: GitHub.