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 the guess-input loop of Mastermind's human-codebreaker mode (line 189). The `.expect` converts any `read_line` I/O error — which the surrounding loop is designed to retry for *parse* errors — into a hard crash, defeating the purpose of the input loop.
Source
Thrown at 60_Mastermind/rust/Mastermind/src/main.rs:189
//round loop
loop {
//loop condition
if num_moves > num_guesses {
println!("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!");
println!("THE ACTUAL COMBINATION WAS: {}", answer._as_human_readible_chars());
human_score += num_moves;
print_scores(human_score,computer_score);
break;
}
//input loop
guess = GUESS::new(loop {
println!("\nMOVE # {} GUESS: ", num_moves);
//get player move
let mut raw_input = String::new(); //temp variable to store user input
io::stdin().read_line(&mut raw_input).expect("CANNOT READ INPUT!"); //read user input from standard input and store it to raw_input
//attempt to parse input
if raw_input.trim().eq_ignore_ascii_case("board") {
//print the board state
print_board(&guesses);
continue; //run loop again
}
else if raw_input.trim().eq_ignore_ascii_case("quit") {
//quit the game
println!("QUITTER! MY COMBINATION WAS: {}\nGOOD BYE", answer._as_human_readible_words());
return; //exit the game
}
else {
//parse input for a code
match CODE::new_from_string(raw_input, num_colors) {
Some(code) => {
//ensure code is correct length
if code.code.len() != num_positions { // if notView on GitHub (pinned to 5301155192)
Solutions
- Change the `.expect` to a `match` that on `Ok(0)` (EOF) prints a graceful exit message and `return`s or `break`s from the game loop.
- On a non-fatal `Err`, print an error and `continue` the input loop rather than crashing.
- Provide a `--no-interactive` mode or feed input from a file with enough lines to complete the game.
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 ended. Exiting game."); return; }
Ok(_) => {}
Err(e) => { eprintln!("Input error: {}", e); continue; }
} Defensive patterns
Strategy: retry
Validate before calling
// Ensure input stream has content before entering the game loop
use std::io::IsTerminal;
if io::stdin().is_terminal() { /* safe to prompt interactively */ } Type guard
fn try_read_line() -> Option<String> {
let mut buf = String::new();
(io::stdin().read_line(&mut buf).ok()? > 0).then_some(buf)
} Try / catch
match io::stdin().read_line(&mut raw_input) {
Ok(0) => { println!("Input ended."); return; }
Ok(_) => { /* parse input */ }
Err(e) => { eprintln!("{}", e); continue; }
} Prevention
- Use retry loops for parse errors but handle I/O errors separately with graceful exit.
- Ensure piped input files provide enough lines for every prompt in every game phase.
- Add a 'quit' command check as an escape hatch in long input loops.
When it happens
Trigger: The player's stdin stream fails at the OS level (not a bad guess, which is handled by the `CODE::new_from_string` fallback). This occurs when stdin is closed mid-game, redirected from a file that ends before the game is over, or when running under a non-interactive runner. The `"board"` and `"quit"` string checks happen *after* `read_line` succeeds, so they cannot prevent this panic.
Common situations: Piping a scripted input file that has fewer lines than the game needs. Running the game in a CI pipeline or Docker container without an interactive TTY. A terminal emulator crash or SSH disconnect mid-session.
Related errors
- Failed to read the line
- No valid input
- something went wrong getting user guess
- something went wrong getting secret from user
- CANNOT READ INPUT!
AI-assisted analysis of coding-horror/basic-computer-games@5301155192 (2026-08-13).
Data as JSON: /api/errors/1d9d9a340d48c628.
Report an issue: GitHub.