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

  1. Always pair bare_key = BareKey::Char with character: Some("a".to_string()) containing the character.
  2. If the key is not a printable character, send the matching named BareKey variant (Enter, Tab, Esc, ...) instead of Char.
  3. Write a round-trip test data::Key -> KeyWithModifier -> data::Key over your key set.
  4. 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

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


AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16). Data as JSON: /api/errors/cc8e055ba5fa43be. Report an issue: GitHub.