zellij-org/zellij · critical

failed to receive event on channel

Error message

failed to receive event on channel

What it means

The plugin thread's event loop: bus.recv() on the channel carrying PluginInstruction messages returns Err only when every sender has been dropped - the channel is disconnected. Zellij expects senders to outlive the plugin thread, so this fires during shutdown-ordering races (senders torn down before the plugin loop drains) or when another server thread panicked and released its bus sender. The expect then panics the plugin thread, typically ending the session.

Source

Thrown at zellij-server/src/plugins/mod.rs:348

        layout_dir,
        available_layouts,
        available_layout_errors,
        default_mode,
        default_keybinds,
    );

    for run_plugin_or_alias in background_plugins {
        load_background_plugin(
            run_plugin_or_alias,
            &mut wasm_bridge,
            &bus,
            &plugin_aliases,
            initiating_client_id,
        );
    }

    loop {
        let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel");
        err_ctx.add_call(ContextType::Plugin((&event).into()));
        match event {
            PluginInstruction::Load(
                should_float,
                should_be_open_in_place,
                close_replaced_pane,
                pane_title,
                mut run_plugin_or_alias,
                tab_index,
                pane_id_to_replace,
                client_id,
                size,
                cwd,
                focused_plugin_id,
                skip_cache,
                should_focus_plugin,
                floating_pane_coordinates,
                completion_tx,

View on GitHub (pinned to 98a0837077)

Solutions

  1. Recover by starting a fresh session (state in the dead session is lost)
  2. Update zellij - thread teardown ordering is regularly hardened
  3. Reproduce with debug logging and look for an earlier panic in the log; that root cause disconnected the channel
  4. Report the log sequence if no earlier fault exists, since it then indicates a pure shutdown race

Example fix

// before
let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel");

// after - treat disconnect as a shutdown signal
let (event, mut err_ctx) = match bus.recv() {
    Ok(recv) => recv,
    Err(_) => {
        log::info!("plugin bus disconnected; shutting down plugin thread");
        break;
    }
};
Defensive patterns

Strategy: fallback

Try / catch

loop {
    let (event, mut err_ctx) = match bus.recv() {
        Ok(recv) => recv,
        Err(_) => {
            log::info!("plugin bus closed; draining and exiting plugin thread cleanly");
            break;
        }
    };
    err_ctx.add_call(ContextType::Plugin((&event).into()));
    // handle event...
}

Prevention

When it happens

Trigger: Server/session teardown while plugin instructions are still in flight; an earlier panic on a thread that owned a sender, disconnecting the bus under the plugin loop.

Common situations: Exiting immediately after triggering plugin loads; cascading failures where an unrelated thread panic later shows up as this channel disconnect; version regressions in shutdown sequencing.

Related errors


AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16). Data as JSON: /api/errors/17d28eec46c270b7. Report an issue: GitHub.