atuinsh/atuin · error · std::io::Error

Interactive mode requires a terminal

Error message

Interactive mode requires a terminal

What it means

Returned by TerminalWriter::new in interactive search when Atuin is compiled for a target that is neither unix nor windows (the #[cfg(not(any(unix, windows)))] arm at interactive.rs:1466). Interactive mode needs a terminal: stdout when it is a TTY, /dev/tty on unix, or CONOUT$ on Windows; with no platform backend available it fails with io::ErrorKind::Unsupported. This is effectively a build/platform configuration problem, not a runtime environment one.

Source

Thrown at crates/atuin/src/command/client/search/interactive.rs:1467

                .read(true)
                .write(true)
                .open("CONOUT$")?;

            let initial_console_output_cp = unsafe { GetConsoleOutputCP() };
            if initial_console_output_cp != Self::CP_UTF8 {
                unsafe {
                    SetConsoleOutputCP(Self::CP_UTF8);
                }
            }

            Ok(TerminalWriter::ConOut(
                std::io::LineWriter::new(file),
                initial_console_output_cp,
            ))
        }

        #[cfg(not(any(unix, windows)))]
        Err(std::io::Error::new(
            std::io::ErrorKind::Unsupported,
            "Interactive mode requires a terminal",
        ))
    }
}

impl Write for TerminalWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        match self {
            TerminalWriter::Stdout(stdout) => stdout.write(buf),
            #[cfg(unix)]
            TerminalWriter::Tty(file) => file.write(buf),
            #[cfg(windows)]
            TerminalWriter::ConOut(writer, _) => writer.write(buf),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {

View on GitHub (pinned to 202f6ad98e)

Solutions

  1. Run interactive search on a supported platform (unix or windows builds of Atuin)
  2. Use non-interactive search (`atuin search <query>`) which prints results to stdout and never builds a TerminalWriter
  3. If porting, implement a TerminalWriter backend for the target (e.g. open the platform's controlling terminal) behind a new cfg gate
  4. Catch io::ErrorKind::Unsupported in embedding code and degrade to non-interactive output

Example fix

// before
let writer = TerminalWriter::new()?;

// after
let writer = TerminalWriter::new().or_else(|e| {
    if e.kind() == std::io::ErrorKind::Unsupported {
        // fall back to non-interactive output on this platform
    }
    Err(e)
})?;
Defensive patterns

Strategy: fallback

Validate before calling

// Detect the unsupported case before launching the TUI
let interactive_ok = cfg!(any(unix, windows));
if !interactive_ok { /* run non-interactive search path instead */ }

Try / catch

match TerminalWriter::new() {
    Ok(w) => { /* run TUI */ }
    Err(e) if e.kind() == std::io::ErrorKind::Unsupported => {
        // no terminal backend on this platform: fall back to plain output
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Building the atuin binary for an exotic target (wasm32, redox, etc.) where none of the cfg(unix)/cfg(windows) terminal backends compile, then invoking `atuin search -i` (interactive mode), which constructs TerminalWriter.

Common situations: Cross-compiling Atuin to a Tier-3 target; running in a sandbox/wasm environment that maps neither unix nor windows cfg flags; developers porting Atuin hitting the compile-time gap during first run on a new OS.

Related errors


AI-assisted analysis of atuinsh/atuin@202f6ad98e (2026-08-16). Data as JSON: /api/errors/6499ff40fa42df31. Report an issue: GitHub.