xai-org/grok-build · critical

terminal writer stopped

Error message

terminal writer stopped

What it means

The event loop multiplexes the terminal writer's event channel via tokio::select. When writer_event_rx.recv() returns None, the writer task has terminated (channel closed) while the app is still running, so the loop records a startup error outcome, flushes stall telemetry, and aborts with this anyhow error.

Source

Thrown at crates/codegen/xai-grok-pager/src/app/event_loop.rs:2411

            // Leader disconnect: the bridge fires cancel when the IPC channel closes
            // Without this arm the loop would hang because AppView holds the client-side tx, keeping acp_rx open
            _ = connection_cancel.cancelled() => {
                break;
            }

            // Graceful-quit request from the signal handler
            // Kept high in the biased order so a SIGTERM quit isn't starved by an ACP firehose
            _ = quit_notify.notified() => {
                let effs = dispatch::dispatch(Action::Quit, &mut app);
                let _ = process_effects(effs, &mut tasks, &mut app, &progress_tx);
                break;
            }

            writer_event = writer_event_rx.recv() => {
                let Some(writer_event) = writer_event else {
                    app.finish_startup(xai_grok_telemetry::startup::StartupOutcome::Error);
                    flush_pending_stall(&mut stall_rollup);
                    return Err(anyhow::anyhow!("terminal writer stopped"));
                };
                let sequence = match writer_event_sequence(writer_event)
                    .context("terminal output failed")
                {
                    Ok(sequence) => sequence,
                    Err(e) => {
                        app.finish_startup(xai_grok_telemetry::startup::StartupOutcome::Error);
                        flush_pending_stall(&mut stall_rollup);
                        return Err(e);
                    }
                };
                presenter.acknowledge(sequence);
            }

            // Biased order: cancellation/quit, writer acks/failures, ACP, task/progress results, updates, input, and render/poll timers
            // All of them precede the deliberately-last voice STT arm (see its note below)

            // Gated on empty terminal input

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Re-run with logging/RUST_BACKTRACE=1 to find why the writer task exited (panic or I/O error) first
  2. Check that stdout is a valid, writable terminal or pipe and the parent process has not closed it
  3. Verify terminal size/emulator handles the writer's output (try a plain xterm or TERM=xterm-256color)
  4. Inspect writer task code for early returns/aborts on non-fatal I/O errors and make them retry or degrade gracefully

Example fix

// before: writer exits on transient write error
writer.send(line).await?;
// after: tolerate transient failures instead of closing the channel
if writer.send(line).await.is_err() {
    tracing::warn!("terminal write failed; backing off");
    tokio::time::sleep(Duration::from_millis(50)).await;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before launching, ensure stdout is writable
use std::io::Write;
fn stdout_writable() -> bool {
    let mut out = std::io::stdout();
    out.flush().is_ok()
}

Try / catch

match run().await {
    Err(e) if e.to_string().contains("terminal writer stopped") => {
        eprintln!("TUI writer died; re-run in a persistent terminal: {e:#}");
    }
    Err(e) => eprintln!("fatal: {e:#}"),
    Ok(_) => {}
}

Prevention

When it happens

Trigger: The terminal writer task exits early — it panics, returns Err on an unwritable/lost stdout (e.g. output pipe closed by the terminal or pager teardown), or is aborted — dropping its sender so recv() yields None in the select branch.

Common situations: Running the TUI with stdout redirected into a pipe that the consumer closes; writer task crash due to an I/O error on a detached/SSH-disconnected terminal; a bug causing writer shutdown before the event loop exits.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/d0947360294a3cf9. Report an issue: GitHub.