zellij-org/zellij · error · anyhow::Error

Invalid InputMode value: {}

Error message

Invalid InputMode value: {}

What it means

Thrown while converting a protobuf InputMode integer back into the native InputMode enum. The match covers every known ProtoInputMode variant and falls through to this error for anything else. It signals an out-of-range or unrecognized enum value, which almost always means data corruption or a version mismatch between the two sides of the IPC contract.

Source

Thrown at zellij-utils/src/ipc/protobuf_conversion.rs:3428

}

fn proto_i32_to_input_mode(i: i32) -> Result<InputMode> {
    match ProtoInputMode::from_i32(i) {
        Some(ProtoInputMode::Normal) => Ok(InputMode::Normal),
        Some(ProtoInputMode::Locked) => Ok(InputMode::Locked),
        Some(ProtoInputMode::Resize) => Ok(InputMode::Resize),
        Some(ProtoInputMode::Pane) => Ok(InputMode::Pane),
        Some(ProtoInputMode::Tab) => Ok(InputMode::Tab),
        Some(ProtoInputMode::Scroll) => Ok(InputMode::Scroll),
        Some(ProtoInputMode::EnterSearch) => Ok(InputMode::EnterSearch),
        Some(ProtoInputMode::Search) => Ok(InputMode::Search),
        Some(ProtoInputMode::RenameTab) => Ok(InputMode::RenameTab),
        Some(ProtoInputMode::RenamePane) => Ok(InputMode::RenamePane),
        Some(ProtoInputMode::Session) => Ok(InputMode::Session),
        Some(ProtoInputMode::Move) => Ok(InputMode::Move),
        Some(ProtoInputMode::Prompt) => Ok(InputMode::Prompt),
        Some(ProtoInputMode::Tmux) => Ok(InputMode::Tmux),
        _ => Err(anyhow!("Invalid InputMode value: {}", i)),
    }
}

// Additional helper functions for Action conversion
fn resize_to_proto_i32(resize: crate::data::Resize) -> i32 {
    use crate::client_server_contract::client_server_contract::ResizeType;
    match resize {
        crate::data::Resize::Increase => ResizeType::Increase as i32,
        crate::data::Resize::Decrease => ResizeType::Decrease as i32,
    }
}

fn direction_to_proto_i32(direction: crate::data::Direction) -> i32 {
    use crate::client_server_contract::client_server_contract::Direction as ProtoDirection;
    match direction {
        crate::data::Direction::Left => ProtoDirection::Left as i32,
        crate::data::Direction::Right => ProtoDirection::Right as i32,
        crate::data::Direction::Up => ProtoDirection::Up as i32,

View on GitHub (pinned to 98a0837077)

Solutions

  1. Align client and server to the same zellij build so the enum sets match
  2. Regenerate the protobuf bindings (client_server_contract) after editing the .proto and rebuild both sides
  3. If accepting untrusted input, validate the i32 against the known variant set before converting

Example fix

// before
let mode = InputMode::try_from(proto_mode_i32)?; // may fail on unknown value

// after
use crate::client_server_contract::client_server_contract::InputMode as ProtoInputMode;
fn is_known_input_mode(v: i32) -> bool {
    matches!(v, x if x == ProtoInputMode::Normal as i32
        || x == ProtoInputMode::Locked as i32
        || x == ProtoInputMode::Resize as i32
        || x == ProtoInputMode::Pane as i32
        || x == ProtoInputMode::Tab as i32)
}
let mode = if is_known_input_mode(proto_mode_i32) { InputMode::try_from(proto_mode_i32)? } else { InputMode::Normal };
Defensive patterns

Strategy: validation

Validate before calling

const KNOWN_INPUT_MODES: &[i32] = &[
    ProtoInputMode::Normal as i32, ProtoInputMode::Locked as i32,
    ProtoInputMode::Resize as i32, ProtoInputMode::Pane as i32,
    ProtoInputMode::Tab as i32, ProtoInputMode::Scroll as i32,
    ProtoInputMode::EnterSearch as i32, ProtoInputMode::Search as i32,
    ProtoInputMode::RenameTab as i32, ProtoInputMode::RenamePane as i32,
    ProtoInputMode::Session as i32, ProtoInputMode::Move as i32,
    ProtoInputMode::Prompt as i32, ProtoInputMode::Tmux as i32,
];
fn is_known_input_mode(v: i32) -> bool { KNOWN_INPUT_MODES.contains(&v) }

Type guard

fn is_valid_input_mode(v: i32) -> bool {
    // regenerate this list from the proto enum when the contract changes
    KNOWN_INPUT_MODES.contains(&v)
}

Try / catch

let mode = InputMode::try_from(proto_value)
    .with_context(|| format!("rejected InputMode value {} (version skew?)", proto_value))?;

Prevention

When it happens

Trigger: Calling the InputMode TryFrom conversion with an i32 that does not correspond to any ProtoInputMode variant: a newer enum value sent to an older binary, a corrupted message, or a manually constructed payload with an arbitrary integer.

Common situations: Mixing zellij client and server of different versions after a new InputMode variant was added; fuzzed or hand-written protobuf payloads; stale compiled contract after regenerating the .proto files.

Related errors


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