{"record":{"id":"b82fc79589b0bcbb","repo":"zellij-org/zellij","slug":"failed-to-send-message-to-channel-b82fc7","errorCode":null,"errorMessage":"failed to send message to channel","messagePattern":"failed to send message to channel","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"zellij-utils/src/errors.rs","lineNumber":962,"sourceCode":"    ///\n    /// Takes the `SendError` and creates an `anyhow` error type with the message that was sent\n    /// (formatted as string), attaching the [`ErrorContext`] as anyhow context to it.\n    impl<T: std::fmt::Debug, U> ToAnyhow<U>\n        for Result<U, crate::channels::SendError<(T, ErrorContext)>>\n    {\n        fn to_anyhow(self) -> anyhow::Result<U> {\n            match self {\n                Ok(val) => anyhow::Ok(val),\n                Err(e) => {\n                    let (msg, context) = e.into_inner();\n                    if *crate::consts::DEBUG_MODE.get().unwrap_or(&true) {\n                        Err(anyhow::anyhow!(\n                            \"failed to send message to channel: {:#?}\",\n                            msg\n                        ))\n                        .with_context(|| context.to_string())\n                    } else {\n                        Err(anyhow::anyhow!(\"failed to send message to channel\"))\n                            .with_context(|| context.to_string())\n                    }\n                },\n            }\n        }\n    }\n\n    impl<U> ToAnyhow<U> for Result<U, std::sync::PoisonError<U>> {\n        fn to_anyhow(self) -> anyhow::Result<U> {\n            match self {\n                Ok(val) => anyhow::Ok(val),\n                Err(e) => {\n                    if *crate::consts::DEBUG_MODE.get().unwrap_or(&true) {\n                        Err(anyhow::anyhow!(\"cannot acquire poisoned lock for {e:#?}\"))\n                    } else {\n                        Err(anyhow::anyhow!(\"cannot acquire poisoned lock\"))\n                    }\n                },","sourceCodeStart":944,"sourceCodeEnd":980,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-utils/src/errors.rs#L944-L980","documentation":"Production (non-debug) variant of the ToAnyhow implementation for SendError in zellij-utils/errors.rs: a message sent over an internal channel could not be delivered because the receiver was dropped. The ErrorContext is still attached so the error chain shows which subsystem dispatched the send, but the unsent payload is omitted for a smaller message. Fired whenever DEBUG_MODE is false/unset and .to_anyhow() is applied to a failed send.","triggerScenarios":"The same send-after-receiver-death race as the debug variant: worker thread owning the receiver has exited (panic, shutdown, disconnect) while another thread calls send(...).to_anyhow()? on the shared channel.","commonSituations":"Session teardown racing pending input; earlier panic in screen/router thread; abrupt client disconnect; long-running automation scripting the CLI against a server that is closing.","solutions":["Search the log above this error for the original panic or shutdown of the receiver thread and address that root cause","Restart the session to restore consistent channel state","Reproduce with `zellij --debug` (or set debug mode) to get the debug variant that names the unsent message","Update zellij to pick up concurrency fixes; report persistent reproduction"],"exampleFix":"// before\nbus.senders.send_to_screen.send((screen_msg, ErrorContext::new())).to_anyhow()?;\n\n// after: treat a dead receiver as termination, not a fatal error\nif let Err(e) = bus.senders.send_to_screen.send((screen_msg, ErrorContext::new())).to_anyhow() {\n    log::warn!(\"screen channel closed, stopping emitter: {e:#}\");\n    break;\n}","handlingStrategy":"try-catch","validationCode":"if !sender.is_connected_to_any_receiver() {\n    log::debug!(\"receiver dropped; not sending\");\n    return Ok(());\n}","typeGuard":null,"tryCatchPattern":"match sender.send((msg, ErrorContext::new())).to_anyhow() {\n    Ok(_) => {}\n    Err(e) => {\n        log::warn!(\"channel closed, stopping emitter: {e:#}\");\n        break; // graceful: unwind this producer instead of failing the caller\n    },\n}","preventionTips":["Mirror shutdown signals (crossbeam Select/threads) so producers exit before consumers drop","Run with debug mode when diagnosing to get the payload-bearing variant of this error","Log receiver-thread lifecycle (start/exit/panic) to correlate with send failures","Avoid sending from timers/plugins after initiating session quit"],"tags":["channel","concurrency","shutdown","ipc"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}