zellij-org/zellij · error · anyhow::Error
Unspecified exit reason
Error message
Unspecified exit reason
What it means
Thrown by TryFrom<ProtoExitReason> for ExitReason when the protobuf enum value is Unspecified. In proto3, Unspecified (=0) is the default value, so it typically means the sender never set the exit_reason field. The converter deliberately refuses to guess an exit reason instead of silently mapping it to Normal.
Source
Thrown at zellij-utils/src/ipc/protobuf_conversion.rs:3369
ExitReason::CustomExitStatus(_status) => ProtoExitReason::CustomExitStatus,
}
}
}
impl TryFrom<ProtoExitReason> for ExitReason {
type Error = anyhow::Error;
fn try_from(reason: ProtoExitReason) -> Result<Self> {
match reason {
ProtoExitReason::Normal => Ok(ExitReason::Normal),
ProtoExitReason::NormalDetached => Ok(ExitReason::NormalDetached),
ProtoExitReason::ForceDetached => Ok(ExitReason::ForceDetached),
ProtoExitReason::CannotAttach => Ok(ExitReason::CannotAttach),
ProtoExitReason::Disconnect => Ok(ExitReason::Disconnect),
ProtoExitReason::WebClientsForbidden => Ok(ExitReason::WebClientsForbidden),
ProtoExitReason::KickedByHost => Ok(ExitReason::KickedByHost),
ProtoExitReason::Error => Ok(ExitReason::Error("Protobuf error".to_string())),
ProtoExitReason::CustomExitStatus => Ok(ExitReason::CustomExitStatus(0)),
ProtoExitReason::Unspecified => Err(anyhow!("Unspecified exit reason")),
}
}
}
impl From<HostTerminalThemeMode> for ProtoHostTerminalThemeIndication {
fn from(mode: HostTerminalThemeMode) -> Self {
match mode {
HostTerminalThemeMode::Dark => ProtoHostTerminalThemeIndication::Dark,
HostTerminalThemeMode::Light => ProtoHostTerminalThemeIndication::Light,
}
}
}
impl From<ProtoHostTerminalThemeIndication> for HostTerminalThemeMode {
fn from(mode: ProtoHostTerminalThemeIndication) -> Self {
match mode {
ProtoHostTerminalThemeIndication::Dark => HostTerminalThemeMode::Dark,
ProtoHostTerminalThemeIndication::Light => HostTerminalThemeMode::Light,View on GitHub (pinned to 98a0837077)
Solutions
- Update both client and server to matching zellij versions so exit_reason is always populated
- Fix the sender to always set a concrete exit_reason value (never rely on proto3 defaults)
- If you control the conversion, map Unspecified to a defined fallback such as ExitReason::Normal instead of erroring
Example fix
// before
ProtoExitReason::Unspecified => Err(anyhow!("Unspecified exit reason")),
// after (defensive default)
ProtoExitReason::Unspecified => Ok(ExitReason::Normal), Defensive patterns
Strategy: validation
Validate before calling
use zellij_utils::interprocess::contract::ExitReason as ProtoExitReason; // adjust path to generated contract
fn exit_reason_is_set(reason: ProtoExitReason) -> bool {
!matches!(reason, ProtoExitReason::Unspecified)
} Type guard
fn is_concrete_exit_reason(r: ProtoExitReason) -> bool {
!matches!(r, ProtoExitReason::Unspecified)
} Try / catch
match ProtoExitReason::try_from(raw) {
Ok(reason) => use_reason(reason),
Err(e) if e.to_string().contains("Unspecified exit reason") => {
log::warn!("exit reason unset by peer; treating as normal");
use_reason(ExitReason::Normal);
},
Err(e) => return Err(e),
} Prevention
- Always set enum fields explicitly when building protobuf messages; never rely on proto3 zero defaults
- Pin client and server to the same zellij version to keep the IPC contract aligned
- Add round-trip tests for every enum crossing the IPC boundary
When it happens
Trigger: Decoding an ExitReason protobuf message whose enum field was never populated (proto3 zero-value), e.g. a client/server built from a different contract version, or a hand-crafted/malformed IPC payload passed to the conversion in zellij-utils/src/ipc/protobuf_conversion.rs:3369.
Common situations: Version skew between zellij client and server where one side stops setting exit_reason; test fixtures or custom clients that construct the proto message without setting the field.
Related errors
- SkipConfirm missing action
- NewTiledPluginPane missing plugin
- NewFloatingPluginPane missing plugin
- NewInPlacePluginPane missing plugin
- StartOrReloadPlugin missing plugin
AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16).
Data as JSON: /api/errors/acd3412fd9b83783.
Report an issue: GitHub.