zellij-org/zellij · error
Invalid KeyModifier value: {}
Error message
Invalid KeyModifier value: {} What it means
Thrown by key_modifier_from_proto_i32 (zellij-utils/src/ipc/enum_conversions.rs) when ProtoKeyModifier::from_i32 returns None: a key_modifiers entry carries an i32 that is not a valid KeyModifier discriminant. Mirror of [76] for the modifier enum; in-range-but-unset values are reported as [75] instead.
Source
Thrown at zellij-utils/src/ipc/enum_conversions.rs:137
// 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::from_i32(value).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 i32
}
pub fn key_modifier_from_proto_i32(value: i32) -> Result<KeyModifier> {
let proto_modifier = ProtoKeyModifier::from_i32(value)
.ok_or_else(|| anyhow!("Invalid KeyModifier value: {}", value))?;
proto_modifier.try_into()
}
View on GitHub (pinned to 5cb5df5cce)
Solutions
- Use matching zellij releases on both IPC endpoints.
- Emit modifiers only via key_modifier_to_proto_i32 / `KeyModifier::X as i32`.
- Guard inbound lists: validate each i32 with ProtoKeyModifier::from_i32(...).is_some() and reject the frame otherwise.
Example fix
// before
let mods: Result<Vec<_>> = raw_mods.iter().map(|m| key_modifier_from_proto_i32(*m)).collect(); // Err("Invalid KeyModifier value: 42")
// after: validate before converting
let mods: Vec<KeyModifier> = raw_mods.iter()
.filter(|m| ProtoKeyModifier::from_i32(**m).is_some())
.map(|m| key_modifier_from_proto_i32(*m).unwrap())
.collect::<Result<_>>()?; Defensive patterns
Strategy: validation
Validate before calling
// validate each modifier discriminant before conversion
let mods: Result<Vec<KeyModifier>> = raw_mods
.into_iter()
.filter(|m| ProtoKeyModifier::from_i32(*m).is_some())
.map(key_modifier_from_proto_i32)
.collect(); Type guard
fn is_known_modifier(v: i32) -> bool {
ProtoKeyModifier::from_i32(v).is_some()
} Try / catch
match key_modifier_from_proto_i32(value) {
Ok(m) => Some(m),
Err(e) if e.to_string().starts_with("Invalid KeyModifier value") => {
log::warn!("unknown KeyModifier discriminant {value}; entry skipped");
None
},
Err(e) => return Err(e),
} Prevention
- Same zellij version on every IPC endpoint; enum additions only flow forward with matching releases.
- Use key_modifier_to_proto_i32 for all outbound modifiers.
- Validate repeated i32 fields in one pass at the boundary and drop unknown values with a warning.
When it happens
Trigger: A modifier i32 outside the Ctrl/Alt/Shift/Super/Unspecified range — newer client sending a modifier an older server lacks, handcrafted frames with arbitrary numbers, or arithmetic producing invalid discriminants.
Common situations: Mixed zellij versions between client and server; custom clients guessing numeric modifier codes; fuzzed or corrupted IPC input.
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 BareKey value: {}
- Unspecified key modifier
- Character key needs character data
- Unspecified bare key
- Missing pixel_dimensions
AI-assisted analysis of zellij-org/zellij@5cb5df5cce (2026-08-19).
Data as JSON: /api/errors/3164fbbd3ba25389.
Report an issue: GitHub.