coding-horror/basic-computer-games · error

failed to read input

Error message

failed to read input

What it means

A panic via .expect("failed to read input") on io::stdin().read_line() in get_dollar_value_in_cents_from_user() of the Change Rust port, used to read a dollar amount. read_line returns Err only on I/O-level failure (closed stdin, EOF, broken pipe); non-numeric characters are filtered out afterward (the code keeps only digits and the first '.'). The expect thus aborts only when stdin itself cannot be read.

Source

Thrown at 22_Change/rust/src/main.rs:132

}

/**
 * get number of money from user input
 */
fn get_dollar_value_in_cents_from_user(prompt:&str) -> i16 {
    let mut value:i16;
    //input loop
    loop {
        //data
        let mut raw_input = String::new();

        //print prompt
        print!("{}",prompt);
        //flush std out // allows prompt to be on same line as input
        stdout().flush().expect("failed to flush");

        //get input
        io::stdin().read_line(&mut raw_input).expect("failed to read input");
        //filter out characters that aren't numbers or '.'
        let mut no_prior_periods = true;
        raw_input = raw_input.chars().filter(|c| {
            if c.eq_ignore_ascii_case(&'.') && no_prior_periods {
                no_prior_periods = false;
                true
            } else {
                c.is_ascii_digit()
            }
        }).collect();

        //should only be (at most) 1 .
        if !raw_input.contains(".") { raw_input += ".00";} //if there are none, add one

        //ensure there are at least 2 trailing digits
        if raw_input[raw_input.find('.').unwrap_or(raw_input.len())..].len() <= 2 { //if a slice of the string from the . onwards is less than or equal to 2, add two 0's to the end
            raw_input += "00"
        }

View on GitHub (pinned to 5301155192)

Solutions

  1. Provide a numeric line for each amount prompt in piped input.
  2. Run interactively so stdin remains open.
  3. Swap .expect for a match that returns a default or exits cleanly on read error.

Example fix

// before
io::stdin().read_line(&mut raw_input).expect("failed to read input");

// after
if io::stdin().read_line(&mut raw_input).is_err() {
    println!("\nUnable to read input. Exiting.");
    std::process::exit(1);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure stdin is open / has lines before prompting; provide a numeric line per amount prompt when piping.

Try / catch

// Replace .expect with a match
match io::stdin().read_line(&mut raw_input) {
    Ok(_) => { /* filter digits, parse cents */ }
    Err(_) | Ok(0) => { println!("Input unavailable. Exiting."); std::process::exit(1); }
}

Prevention

When it happens

Trigger: stdin closed or exhausted before the amount prompt is answered; redirected input that ends; broken pipe to stdin; `< /dev/null`.

Common situations: Piped input fixtures with too few lines; headless/CI runs with no TTY; a feeder script closing stdin after a fixed count.

Related errors


AI-assisted analysis of coding-horror/basic-computer-games@5301155192 (2026-08-13). Data as JSON: /api/errors/94946ae0598a79a9. Report an issue: GitHub.