Hmbown/CodeWhale · error · std::io::Error

terminal input pump did not pause before launching editor

Error message

terminal input pump did not pause before launching editor

What it means

TimedOut returned by the pause handshake performed before launching an external editor ($EDITOR). The UI sets a paused flag and polls a paused_ack flag until TERMINAL_INPUT_CHILD_PAUSE_TIMEOUT; if the input pump thread does not acknowledge the pause in time, the launch is aborted and both flags are reset, so the editor never starts while the pump is still reading stdin (which would steal its keystrokes).

Source

Thrown at crates/tui/src/tui/ui.rs:602

    fn stalled_for(&self, now: Instant) -> Duration {
        now.saturating_duration_since(self.last_alive_at.get())
    }

    fn pause_for_child_terminal(&self) -> io::Result<()> {
        self.paused.store(true, Ordering::Release);
        if self.handle.is_none() {
            self.paused_ack.store(true, Ordering::Release);
            self.mark_alive();
            return Ok(());
        }

        let deadline = Instant::now() + TERMINAL_INPUT_CHILD_PAUSE_TIMEOUT;
        while !self.paused_ack.load(Ordering::Acquire) {
            if Instant::now() >= deadline {
                self.paused_ack.store(false, Ordering::Release);
                self.paused.store(false, Ordering::Release);
                return Err(io::Error::new(
                    io::ErrorKind::TimedOut,
                    "terminal input pump did not pause before launching editor",
                ));
            }
            thread::sleep(TERMINAL_INPUT_CHILD_PAUSE_POLL_INTERVAL);
        }
        self.mark_alive();
        Ok(())
    }

    fn resume_after_child_terminal(&self) {
        self.paused_ack.store(false, Ordering::Release);
        self.paused.store(false, Ordering::Release);
        self.mark_alive();
    }

    /// Replace a wedged pump thread with a freshly spawned one.
    ///

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Simply retry the editor action — the handshake resets state cleanly on timeout, so a retry is safe
  2. Pause typing/generating events for a moment before launching the editor
  3. If it fails repeatedly, capture diagnostics: the pump thread is likely wedged; report the terminal type and what preceded the hang
  4. Reduce terminal multiplexing layers (nested tmux/screen) known to stutter input delivery
Defensive patterns

Strategy: retry

Type guard

fn is_editor_pause_timeout(e: &std::io::Error) -> bool {
    e.kind() == std::io::ErrorKind::TimedOut
        && e.to_string().contains("did not pause before launching editor")
}

Try / catch

for attempt in 1..=2 {
    match input.pause_for_child_terminal() {
        Ok(()) => { editor::spawn(&editor_cmd)?; break; }
        Err(e) if is_editor_pause_timeout(&e) && attempt < 2 => { continue; } // flags were reset; retry is safe
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: Opening an external editor while the input pump thread is stuck or too busy to observe the pause flag — e.g. the pump is blocked inside a terminal read or buried under an event flood, or the system is so loaded the poll loop misses the deadline.

Common situations: Heavy key-repeat/mouse-flood right before invoking the editor; slow or frozen terminal I/O (NFS home, remote X/SSH latency); a pump thread wedged by a terminal library edge case; extremely loaded machine making the polling thread starve.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/65ca56d1acac1457. Report an issue: GitHub.