{"record":{"id":"acd3412fd9b83783","repo":"zellij-org/zellij","slug":"unspecified-exit-reason","errorCode":null,"errorMessage":"Unspecified exit reason","messagePattern":"Unspecified exit reason","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"zellij-utils/src/ipc/protobuf_conversion.rs","lineNumber":3369,"sourceCode":"            ExitReason::CustomExitStatus(_status) => ProtoExitReason::CustomExitStatus,\n        }\n    }\n}\n\nimpl TryFrom<ProtoExitReason> for ExitReason {\n    type Error = anyhow::Error;\n    fn try_from(reason: ProtoExitReason) -> Result<Self> {\n        match reason {\n            ProtoExitReason::Normal => Ok(ExitReason::Normal),\n            ProtoExitReason::NormalDetached => Ok(ExitReason::NormalDetached),\n            ProtoExitReason::ForceDetached => Ok(ExitReason::ForceDetached),\n            ProtoExitReason::CannotAttach => Ok(ExitReason::CannotAttach),\n            ProtoExitReason::Disconnect => Ok(ExitReason::Disconnect),\n            ProtoExitReason::WebClientsForbidden => Ok(ExitReason::WebClientsForbidden),\n            ProtoExitReason::KickedByHost => Ok(ExitReason::KickedByHost),\n            ProtoExitReason::Error => Ok(ExitReason::Error(\"Protobuf error\".to_string())),\n            ProtoExitReason::CustomExitStatus => Ok(ExitReason::CustomExitStatus(0)),\n            ProtoExitReason::Unspecified => Err(anyhow!(\"Unspecified exit reason\")),\n        }\n    }\n}\n\nimpl From<HostTerminalThemeMode> for ProtoHostTerminalThemeIndication {\n    fn from(mode: HostTerminalThemeMode) -> Self {\n        match mode {\n            HostTerminalThemeMode::Dark => ProtoHostTerminalThemeIndication::Dark,\n            HostTerminalThemeMode::Light => ProtoHostTerminalThemeIndication::Light,\n        }\n    }\n}\n\nimpl From<ProtoHostTerminalThemeIndication> for HostTerminalThemeMode {\n    fn from(mode: ProtoHostTerminalThemeIndication) -> Self {\n        match mode {\n            ProtoHostTerminalThemeIndication::Dark => HostTerminalThemeMode::Dark,\n            ProtoHostTerminalThemeIndication::Light => HostTerminalThemeMode::Light,","sourceCodeStart":3351,"sourceCodeEnd":3387,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-utils/src/ipc/protobuf_conversion.rs#L3351-L3387","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nProtoExitReason::Unspecified => Err(anyhow!(\"Unspecified exit reason\")),\n\n// after (defensive default)\nProtoExitReason::Unspecified => Ok(ExitReason::Normal),","handlingStrategy":"validation","validationCode":"use zellij_utils::interprocess::contract::ExitReason as ProtoExitReason; // adjust path to generated contract\nfn exit_reason_is_set(reason: ProtoExitReason) -> bool {\n    !matches!(reason, ProtoExitReason::Unspecified)\n}","typeGuard":"fn is_concrete_exit_reason(r: ProtoExitReason) -> bool {\n    !matches!(r, ProtoExitReason::Unspecified)\n}","tryCatchPattern":"match ProtoExitReason::try_from(raw) {\n    Ok(reason) => use_reason(reason),\n    Err(e) if e.to_string().contains(\"Unspecified exit reason\") => {\n        log::warn!(\"exit reason unset by peer; treating as normal\");\n        use_reason(ExitReason::Normal);\n    },\n    Err(e) => return Err(e),\n}","preventionTips":["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"],"tags":["protobuf","ipc","serialization","exit-reason"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}