zellij-org/zellij · error
failed to send message to channel
Error message
failed to send message to channel
What it means
The non-DEBUG_MODE variant of the same ToAnyhow impl for channel SendError<(T, ErrorContext)> in zellij-utils/src/errors.rs: the send failed because the receiver side was dropped, and the message payload is withheld in production builds. The attached ErrorContext string identifies the sending subsystem.
Solutions
- Confirm the target session/thread still exists (zellij list-sessions, process list for the zellij server).
- Re-run with DEBUG_MODE enabled to get variant [68] with the full undeliverable message — that shows exactly what was being sent when the channel died.
- Search logs upward for the first panic/exit — that closed the channel; report it with backtrace.
- Update zellij.
Defensive patterns
Strategy: try-catch
Try / catch
// production builds: same handling, generic message
match sender.send((msg, ErrorContext::new())).to_anyhow() {
Ok(_) => {},
Err(e) if e.to_string().starts_with("failed to send message to channel") => {
log::warn!("peer thread exited; shutting down this worker");
return;
},
Err(e) => return Err(e),
} Prevention
- Enable DEBUG_MODE during diagnosis to upgrade this to variant [68] with the full message dump.
- Design worker threads so the receiver's exit also signals the sender (shared AtomicBool/JOB flag), avoiding sends to dead peers.
- Log receiver-thread panics loudly so the closed-channel symptom is never the first evidence.
When it happens
Trigger: Identical mechanism to the debug variant: .send((msg, ErrorContext)).to_anyhow() on a channel whose consumer thread has exited (panic, teardown, or dropped receiver), with consts::DEBUG_MODE off so only the generic message is shown.
Common situations: Production/default builds where a session was killed while dependent threads still sent; a background thread panicked silently earlier; detach/exit races between client and server threads.
Related errors
- failed to send message to channel
- cannot acquire poisoned lock
- cannot acquire poisoned lock for
- Character key needs character data
- Failed to find active pane
AI-assisted analysis of zellij-org/zellij@bf8d23a4f7 (2026-08-19).
Data as JSON: /api/errors/b82fc79589b0bcbb.
Report an issue: GitHub.
Appendix: source
Thrown at zellij-utils/src/errors.rs:972
///
/// 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) => {
if *crate::consts::DEBUG_MODE.get().unwrap_or(&true) {
Err(anyhow::anyhow!("cannot acquire poisoned lock for {e:#?}"))
} else {
Err(anyhow::anyhow!("cannot acquire poisoned lock"))
}
},View on GitHub (pinned to bf8d23a4f7)