zellij-org/zellij · error · anyhow::Error
failed to send message to channel: {:#?}
Error message
failed to send message to channel: {:#?} What it means
Debug-mode variant of the ToAnyhow implementation for crossbeam/mpc SendError in zellij-utils/errors.rs. Sending a (T, ErrorContext) message failed because the receiving end of the channel was dropped — typically the owning thread exited via shutdown, disconnect, or a panic. In DEBUG_MODE the unsent message itself is pretty-printed into the error before the ErrorContext is attached, so you can see exactly which message could not be delivered.
Source
Thrown at zellij-utils/src/errors.rs:956
}
/// `SendError` doesn't satisfy `anyhow`s trait requirements due to `T` possibly being a
/// `PluginInstruction` type, which wraps an `mpsc::Send` and isn't `Sync`. Due to this, in turn,
/// the whole error type isn't `Sync` and doesn't work with `anyhow` (or pretty much any other
/// error handling crate).
///
/// Takes the `SendError` and creates an `anyhow` error type with the message that was sent
/// (formatted as string), attaching the [`ErrorContext`] as anyhow context to it.
impl<T: std::fmt::Debug, U> ToAnyhow<U>
for Result<U, crate::channels::SendError<(T, ErrorContext)>>
{
fn to_anyhow(self) -> anyhow::Result<U> {
match self {
Ok(val) => anyhow::Ok(val),
Err(e) => {
let (msg, context) = e.into_inner();
if *crate::consts::DEBUG_MODE.get().unwrap_or(&true) {
Err(anyhow::anyhow!(
"failed to send message to channel: {:#?}",
msg
))
.with_context(|| context.to_string())
} else {
Err(anyhow::anyhow!("failed to send message to channel"))
.with_context(|| context.to_string())
}
},
}
}
}
impl<U> ToAnyhow<U> for Result<U, std::sync::PoisonError<U>> {
fn to_anyhow(self) -> anyhow::Result<U> {
match self {
Ok(val) => anyhow::Ok(val),
Err(e) => {View on GitHub (pinned to 98a0837077)
Solutions
- Look earlier in the logs for a panic or exit in the thread that owned the channel receiver — this error is almost always the symptom, not the cause
- Restart the zellij session (`zellij --new-session ...`) to rebuild the channel fabric
- Avoid force-killing the server while plugins are scheduling actions; use the quit action for graceful teardown
- Upgrade zellij if the receiver-thread panic is a known fixed bug; report with the panic backtrace if not
Example fix
// before
sender.send((msg, ErrorContext::new())).to_anyhow()?; // errors after receiver dies
// after: stop sending once the peer is gone
if !sender.is_connected_to_any_receiver() {
log::warn!("dropping message, receiver gone");
return Ok(());
}
sender.send((msg, ErrorContext::new())).to_anyhow()?; Defensive patterns
Strategy: try-catch
Validate before calling
// before sending on a crossbeam bus sender
if !sender.is_connected_to_any_receiver() {
// receiver thread is gone; sending would fail
return Ok(());
} Try / catch
use zellij_utils::errors::prelude::*;
if let Err(e) = sender.send((msg, ErrorContext::new())).to_anyhow() {
log::warn!("dropping message, channel closed: {e:#}");
// treat as termination of this emitter loop, do not propagate
break;
} Prevention
- Design senders to stop (break their loop) on the first SendError instead of retrying sends
- Establish shutdown ordering: producers stop before consumers are dropped
- Check is_connected_to_any_receiver() before sends in teardown paths
- Never treat a send failure as the root cause — always hunt the earlier receiver panic/exit in logs
When it happens
Trigger: Calling .to_anyhow()? (directly or via the ? operator) on a channel send after the receiver thread has terminated: session teardown while another thread still emits actions, a panicked screen/router/os_input worker that owned the receiver, or a bus/IPC endpoint disconnecting mid-send.
Common situations: Zellij server shutting down while a plugin or scheduled action fires; a worker thread that panicked earlier (this error is the downstream symptom); killing the session process during heavy keybinding/plugin activity; races between client disconnect and pending input routing.
Related errors
- failed to send message to channel
- Failed to convert to protobuf: {:?}
- found no sender to send plugin instruction to
- No tabs left, cannot move clients: {:?} from closed tab
- cannot acquire poisoned lock for {e:#?}
AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16).
Data as JSON: /api/errors/4b735172a91423eb.
Report an issue: GitHub.