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
- Change the return type to `Option<u8>` and return `None` on `Ok(0)` (EOF) or `Err`, letting callers decide.
- Use `match` on `read_line`, printing an error and `continue`-ing the loop on transient errors, exiting on EOF.
- 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
- Return Option<T> from numeric input functions to signal EOF/errors.
- Separate I/O failure handling from parse/range validation in the retry loop.
- Provide sufficient piped input lines for all prompts during testing.
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.