BloopAI/vibe-kanban · error

Failed to read email

Error message

Failed to read email

What it means

`Input::interact_text()` from the dialoguer crate returns a Result; it errors when reading from stdin fails (e.g. no TTY, EOF, or interrupted terminal). The code expects success, so a failed interactive prompt panics with "Failed to read email" in the review CLI's `prompt_email` step.

Source

Thrown at crates/review/src/main.rs:78

    println!("Full terms and conditions and privacy policy: https://review.fast/terms");
    println!();
    println!("Press Enter to accept and continue...");

    let mut input = String::new();
    std::io::stdin().read_line(&mut input).ok();
}

fn prompt_email(config: &mut config::Config) -> String {
    use dialoguer::Input;

    let mut input: Input<String> =
        Input::new().with_prompt("Email address (we'll send a link to the review here, no spam)");

    if let Some(ref saved_email) = config.email {
        input = input.default(saved_email.clone());
    }

    let email: String = input.interact_text().expect("Failed to read email");

    // Save email for next time
    config.email = Some(email.clone());
    if let Err(e) = config.save() {
        debug!("Failed to save config: {}", e);
    }

    email
}

fn create_spinner(message: &str) -> ProgressBar {
    let spinner = ProgressBar::new_spinner();
    spinner.set_style(
        ProgressStyle::default_spinner()
            .template("{spinner:.green} {msg}")
            .expect("Invalid spinner template"),
    );
    spinner.set_message(message.to_string());

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Detect non-interactive environments first (atty/is-terminal on stdin) and require the email via a CLI flag or config file instead of prompting
  2. Replace expect with match on interact_text(): on error, print a friendly message and exit with a nonzero code
  3. Support an --email argument or REVIEW_EMAIL env var so the prompt can be skipped entirely
  4. Allow retrying the prompt once before exiting

Example fix

// before
let email: String = input.interact_text().expect("Failed to read email");
// after
let email: String = input.interact_text()
    .context("Could not read email from terminal. Pass --email or run interactively.")?;
Defensive patterns

Strategy: validation

Validate before calling

if !std::io::stdin().is_terminal() {
    eprintln!("No interactive terminal; pass --email or set REVIEW_EMAIL");
    std::process::exit(1);
}

Try / catch

let email = match input.interact_text() {
    Ok(e) => e,
    Err(e) => { eprintln!("Could not read email: {e}"); std::process::exit(1); }
};

Prevention

When it happens

Trigger: `prompt_email` runs and the terminal read fails: running non-interactively (CI, piped stdin like `echo | review`, no TTY), user presses Ctrl+D (EOF), or the terminal is closed mid-prompt.

Common situations: Running the PR review tool in CI or scripted environments without an interactive terminal; users piping input; Ctrl+C/Ctrl+D during the prompt; Windows console edge cases.

Related errors


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/add86a9d9d93a287. Report an issue: GitHub.