nikivdev/code · error
{} {} requires an interactive terminal (TTY); run this in a
Error message
{} {} requires an interactive terminal (TTY); run this in a terminal tab (e.g. Zed/Ghostty) What it means
This error is thrown by ensure_provider_tty in src/ai.rs:5183 when an AI provider subcommand (such as browse or continue) that requires interactivity is run while stdin or stdout is not a TTY. Provider CLIs like Claude and Codex drive interactive pickers/REPLs, which cannot run when input/output is piped, redirected, or spawned without a terminal. The library bails early with a clear message naming the provider and action rather than letting the underlying CLI fail cryptically.
Source
Thrown at src/ai.rs:5183
connect_event.source = Some("codex-connect".to_string());
let _ = activity_log::append_daily_event(connect_event);
}
fn provider_name(provider: Provider) -> &'static str {
match provider {
Provider::Claude => "claude",
Provider::Codex => "codex",
Provider::Cursor => "cursor",
Provider::All => "ai",
}
}
fn ensure_provider_tty(provider: Provider, action: &str) -> Result<()> {
if io::stdin().is_terminal() && io::stdout().is_terminal() {
return Ok(());
}
bail!(
"{} {} requires an interactive terminal (TTY); run this in a terminal tab (e.g. Zed/Ghostty)",
provider_name(provider),
action
);
}
fn print_provider_session_listing(
provider: Provider,
target: &Path,
sessions: &[AiSession],
json: bool,
) -> Result<()> {
if sessions.is_empty() {
let provider_name = match provider {
Provider::Claude => "Claude",
Provider::Codex => "Codex",
Provider::Cursor => "Cursor",
Provider::All => "AI",View on GitHub (pinned to a747e741ae)
Solutions
- Run the command directly in an interactive terminal tab (e.g. Zed/Ghostty terminal, not a task/output panel)
- Remove any pipe or output redirection so both stdin and stdout are terminals
- Use `ssh -t` when remoting so a pseudo-terminal is allocated
- If automation is the goal, use a non-interactive subcommand (e.g. `f ai codex sessions` with explicit path/query) instead of browse/continue
Example fix
// before (piped, fails) $ f ai codex browse | head -n 5 // after (run interactively) $ f ai codex browse
Defensive patterns
Strategy: validation
Validate before calling
use std::io::IsTerminal;
fn can_run_interactive() -> bool {
std::io::stdin().is_terminal() && std::io::stdout().is_terminal()
}
if !can_run_interactive() {
eprintln!("Run `f ai ... browse/continue` in a real terminal tab.");
return;
} Type guard
fn is_tty() -> bool {
use std::io::IsTerminal;
std::io::stdin().is_terminal() && std::io::stdout().is_terminal()
} Try / catch
match ensure_provider_tty(provider, "browse") {
Ok(()) => { /* launch picker */ }
Err(e) => eprintln!("{e}; open a terminal tab and rerun interactively"),
} Prevention
- Run interactive subcommands directly in a terminal tab, not editor task/output panels
- Never pipe or redirect stdout of browse/continue
- For automation use non-interactive subcommands like `sessions`
- Over SSH use `ssh -t` to allocate a TTY
When it happens
Trigger: Running `f ai claude browse` or `f ai codex continue` (via ensure_provider_tty) when io::stdin().is_terminal() or io::stdout().is_terminal() returns false — e.g. piping output (`| grep`), redirecting (`> file`), running under a non-interactive CI job, or invoking from an editor task without a terminal tab.
Common situations: Running the command from a CI pipeline or cron job; invoking it from an editor-integrated task runner (Zed task, VS Code terminal panel configured as output-only); piping the picker output to jq/grep; running via SSH without `-t`; wrapping in scripts that capture stdout.
Related errors
- no session specified (interactive selection requires a TTY)
- Missing profile: {}
- Could not find agent file for '{}'
- No prompt provided. Usage: f agents run {} "your prompt here
- connect is only supported for Codex sessions; use `f codex c
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/5a5a8c4b0549fcf8.
Report an issue: GitHub.