{"record":{"id":"4b735172a91423eb","repo":"zellij-org/zellij","slug":"failed-to-send-message-to-channel","errorCode":null,"errorMessage":"failed to send message to channel: {:#?}","messagePattern":"failed to send message to channel: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"zellij-utils/src/errors.rs","lineNumber":966,"sourceCode":"    }\n\n    /// `SendError` doesn't satisfy `anyhow`s trait requirements due to `T` possibly being a\n    /// `PluginInstruction` type, which wraps an `mpsc::Send` and isn't `Sync`. Due to this, in turn,\n    /// the whole error type isn't `Sync` and doesn't work with `anyhow` (or pretty much any other\n    /// error handling crate).\n    ///\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) => {","sourceCodeStart":948,"sourceCodeEnd":984,"githubUrl":"https://github.com/zellij-org/zellij/blob/bf8d23a4f774abf27a108da2a1a2689e7d8d0d23/zellij-utils/src/errors.rs#L948-L984","documentation":"Produced by the ToAnyhow impl for Result<_, SendError<(T, ErrorContext)>> in zellij-utils/src/errors.rs when a cross-thread channel send fails because the receiver was dropped. The DEBUG_MODE variant additionally pretty-prints the undeliverable message. The ErrorContext attached as anyhow context tells you which subsystem owned the channel.","triggerScenarios":"Calling .to_anyhow() (or the usual .send(...).to_anyhow() combinators) on a channel whose receiving thread already exited: the thread panicked, the session/thread was torn down, or the receiver was dropped due to a lifecycle bug. Typical senders include client- and plugin-threads talking to the server router/input threads.","commonSituations":"Session killed from another terminal while a client thread still sends; a worker thread (rendering, OS input, plugin host) panicked earlier and its channel closed; shutdown races during detach/exit; plugin thread exited while the server still routes events to it.","solutions":["Check whether the zellij session still exists (zellij list-sessions) — if it died, the send failure is a symptom; reconnect or start a new session.","Look earlier in the log for the original panic or exit of the receiving thread — the poison point, not this send error, is the root cause (set ZELLIJ_LOG_FILE / run with DEBUG_MODE for the verbose message).","Reproduce with RUST_BACKTRACE=1 and file an issue including the panicked thread's backtrace plus this send context.","Update zellij; shutdown-order races between threads are fixed regularly."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// sending across zellij channels: handle receiver-gone explicitly\nuse zellij_utils::errors::ToAnyhow;\n\nif let Err(e) = sender.send((msg, ErrorContext::new())).to_anyhow() {\n    if e.to_string().starts_with(\"failed to send message to channel\") {\n        // receiving thread is gone: session teardown or its panic\n        log::warn!(\"channel closed, stopping sender loop: {e:#}\");\n        return; // exit this loop instead of retrying\n    }\n    return Err(e);\n}","preventionTips":["Stop sender loops as soon as a send fails with a closed channel; never retry a send to a dropped receiver.","Tie channel endpoints to thread lifetimes (drop senders/receivers together) so teardown closes both sides deterministically.","When DEBUG_MODE is on, use the printed undeliverable message to identify which subsystem's receiver died."],"tags":["zellij","rust","channel","send-error","thread-shutdown"],"backgroundTag":"send-on-closed-channel","analyzedSha":"bf8d23a4f774abf27a108da2a1a2689e7d8d0d23","analyzedAt":"2026-08-19T07:42:58.758Z","contentChangedAt":"2026-08-19T07:42:58.758Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}