zellij-org/zellij · error
Unspecified key modifier
Error message
Unspecified key modifier
What it means
Thrown by TryFrom<ProtoKeyModifier> for KeyModifier when the proto modifier enum equals Unspecified (its proto3 default, i32 0). The reverse conversion (From<KeyModifier>) never produces it, so encountering it means an inbound key_modifiers entry was never actually set by the sender.
Source
Thrown at zellij-utils/src/ipc/enum_conversions.rs:115
match modifier {
KeyModifier::Ctrl => ProtoKeyModifier::Ctrl,
KeyModifier::Alt => ProtoKeyModifier::Alt,
KeyModifier::Shift => ProtoKeyModifier::Shift,
KeyModifier::Super => ProtoKeyModifier::Super,
}
}
}
impl TryFrom<ProtoKeyModifier> for KeyModifier {
type Error = anyhow::Error;
fn try_from(modifier: ProtoKeyModifier) -> Result<Self> {
match modifier {
ProtoKeyModifier::Ctrl => Ok(KeyModifier::Ctrl),
ProtoKeyModifier::Alt => Ok(KeyModifier::Alt),
ProtoKeyModifier::Shift => Ok(KeyModifier::Shift),
ProtoKeyModifier::Super => Ok(KeyModifier::Super),
ProtoKeyModifier::Unspecified => Err(anyhow!("Unspecified key modifier")),
}
}
}
// Helper functions for converting between protobuf i32 and enum types
pub fn bare_key_to_proto_i32(key: BareKey) -> i32 {
ProtoBareKey::from(key) as i32
}
pub fn bare_key_from_proto_i32(value: i32) -> Result<BareKey> {
let proto_key = ProtoBareKey::try_from(value)
.ok()
.ok_or_else(|| anyhow!("Invalid BareKey value: {}", value))?;
proto_key.try_into()
}
pub fn key_modifier_to_proto_i32(modifier: KeyModifier) -> i32 {
ProtoKeyModifier::from(modifier) as i32View on GitHub (pinned to bf8d23a4f7)
Solutions
- Only push real modifier discriminants (Ctrl/Alt/Shift/Super) into key_modifiers; omit the list entirely for no modifiers.
- Filter zeros before conversion: retain(|m| *m != 0) on the raw i32 list.
- On the zellij side, align client/server versions if well-formed traffic triggers it.
Example fix
// before
let msg = KeyWithModifier { bare_key: BareKey::Enter as i32, key_modifiers: vec![0], character: None };
// after: empty list = no modifiers
let msg = KeyWithModifier { bare_key: BareKey::Enter as i32, key_modifiers: vec![], character: None }; Defensive patterns
Strategy: type-guard
Validate before calling
// strip unset (0) modifier entries before conversion let mods: Vec<i32> = msg.key_modifiers.into_iter().filter(|m| *m != 0).collect();
Type guard
fn is_valid_modifier(v: i32) -> bool {
ProtoKeyModifier::from_i32(v)
.map(|m| m != ProtoKeyModifier::Unspecified)
.unwrap_or(false)
} Try / catch
match key_modifier_from_proto_i32(m) {
Ok(modifier) => Some(modifier),
Err(e) if e.to_string() == "Unspecified key modifier" => None, // unset entry: skip
Err(e) => return Err(e),
} Prevention
- Build key_modifiers lists only from real discriminants; use an empty list for 'no modifiers'.
- Filter zero/default i32 values out of repeated enum fields at ingestion.
- Unit-test conversion helpers with empty and default-constructed messages.
When it happens
Trigger: A KeyWithModifier's key_modifiers list contains i32 0 (unset/default) — handcrafted frames, defaulted Vec entries, or an intermediate layer that inserts a zero-initialized modifier — and key_modifier_from_proto_i32 / try_into surfaces the error.
Common situations: Custom client code pushing placeholder modifier values; protobuf round-trips through code that reconstructs repeated fields with Default::default(); tests with empty modifier entries.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid KeyModifier value: {}
- Unspecified bare key
- Invalid BareKey value: {}
- Character key needs character data
- Missing pixel_dimensions
AI-assisted analysis of zellij-org/zellij@bf8d23a4f7 (2026-08-19).
Data as JSON: /api/errors/51460a45e08d7bdd.
Report an issue: GitHub.