coding-horror/basic-computer-games · error

CANNOT READ INPUT!

Error message

CANNOT READ INPUT!

What it means

This panic is triggered by `.expect("CANNOT READ INPUT!")` on `io::stdin().read_line()` inside `get_number_from_user_input` in Math Dice (line 115). The function is typed to return `u8` and is designed to loop/retry on bad numeric input or out-of-range values, but the `.expect` converts any stdin I/O failure into a process crash.

Source

Thrown at 61_Math_Dice/rust/src/main.rs:115

    }

    //bottom
    println!(" ----- ");
}

/**
 * gets a integer from user input
 */
fn get_number_from_user_input(prompt: &str, error_message: &str, min:u8, max:u8) -> u8 {
    //input loop
    return loop {
        let mut raw_input = String::new(); // temporary variable for user input that can be parsed later

        //print prompt
        println!("{}", prompt);
        //read user input from standard input, and store it to raw_input
        //raw_input.clear(); //clear input
        io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!");

        //from input, try to read a number
        match raw_input.trim().parse::<u8>() {
            Ok(i) => {
                if i < min || i > max { //input out of desired range
                    println!("{}  ({}-{})", error_message, min,max);
                    continue; // run the loop again
                }
                else {
                    break i;// this escapes the loop, returning i
                }
            },
            Err(e) => {
                println!("{}  {}", error_message, e.to_string().to_uppercase());
                continue; // run the loop again
            }
        };
    };

View on GitHub (pinned to 5301155192)

Solutions

  1. Change the return type to `Option<u8>` and return `None` on `Ok(0)` (EOF) or `Err`, letting callers decide.
  2. Use `match` on `read_line`, printing an error and `continue`-ing the loop on transient errors, exiting on EOF.
  3. Ensure piped input files contain enough numeric lines for all prompts in a game session.

Example fix

// before
io::stdin().read_line(&mut raw_input).expect("CANNOT READ INPUT!");

// after
match io::stdin().read_line(&mut raw_input) {
    Ok(0) => { println!("\nInput closed."); std::process::exit(0); }
    Ok(_) => {}
    Err(e) => { eprintln!("Input error: {}", e); continue; }
}
Defensive patterns

Strategy: try-catch

Validate before calling

use std::io::IsTerminal;
if !io::stdin().is_terminal() {
    eprintln!("Warning: stdin is not interactive.");
}

Type guard

fn get_number(prompt: &str, min: u8, max: u8) -> Option<u8> {
    let mut buf = String::new();
    println!("{}", prompt);
    match io::stdin().read_line(&mut buf) {
        Ok(0) | Err(_) => None,
        Ok(_) => buf.trim().parse::<u8>().ok().filter(|&n| n >= min && n <= max),
    }
}

Try / catch

match io::stdin().read_line(&mut raw_input) {
    Ok(0) => { println!("Input closed."); std::process::exit(0); }
    Ok(_) => { /* parse and validate range */ }
    Err(e) => { eprintln!("{}", e); continue; }
}

Prevention

When it happens

Trigger: Stdin returns `Err` or EOF when the function tries to read a number. The parse and range checks (`raw_input.trim().parse::<u8>()`, `i < min || i > max`) all happen *after* `read_line` succeeds, so they cannot trigger this panic. This is purely an I/O-layer failure.

Common situations: Non-interactive execution. Input piped from a file that ends prematurely. Terminal closed or SSH dropped mid-game. Running under a process supervisor with no stdin.

Related errors


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