coding-horror/basic-computer-games · error
Failed to read line
Error message
Failed to read line
What it means
Rust's std::io::Stdin::read_line reads a line of input into a String and returns io::Result<usize>, where the usize is the number of bytes read (0 means EOF). Calling .expect("Failed to read line") panics only when read_line returns Err(io::Error) — i.e. a genuine I/O failure such as a broken pipe or a bad file descriptor. EOF (Ctrl-D or a closed pipe) returns Ok(0), which does NOT trigger this panic; the empty buffer is then parsed and likely causes a continue or a downstream error instead.
Source
Thrown at 82_Stars/rust_JWB/src/main.rs:71
print_header();
if !read_lowercase_input()?.starts_with('n') {
print_rules();
}
loop {
let secret_number : u8 = rand::thread_rng().gen_range(1..101);
let mut guess_count = 0;
let mut player_won: bool = false;
println!("\n\nOK, I am thinking of a number, start guessing.");
while guess_count < MAX_GUESSES && !player_won {
guess_count += 1;
println!("Your guess? ");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u8 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
// USE THIS STATEMENT FOR DEBUG PURPOSES
// println!("Guess #{} is {}. secret number is {}",guess_count, guess, secret_number);
if guess == secret_number {
// winner winner chicken dinner
player_won = true;
println!("**************************************************!!!");
println!("You got it in {guess_count} guesses!!!");
} else {
print_stars( guess, secret_number) ;
}
}View on GitHub (pinned to 5301155192)
Solutions
- Replace .expect() with a match on read_line's Result: on Ok(0) break the loop (EOF), on Err(e) print a diagnostic and break, on Ok(_) proceed with parsing.
- If the program should simply exit on stdin failure, use std::process::exit(0) inside the Err/EOF arm to avoid an ugly panic backtrace.
- For automated testing, pipe enough lines for every guess plus the game-over prompt, or use a mock stdin crate.
- Propagate the error up by changing the loop body to return Result and using the ? operator so callers decide whether to retry or abort.
Example fix
// before
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
// after
match io::stdin().read_line(&mut guess) {
Ok(0) => { println!("\nInput closed. Goodbye!"); break; }
Ok(_) => {}
Err(e) => { eprintln!("Read error: {e}"); break; }
} Defensive patterns
Strategy: try-catch
Validate before calling
// Check read_line result before parsing the guess
let bytes_read = io::stdin().read_line(&mut guess);
match bytes_read {
Ok(0) => { println!("Input closed."); break; }
Err(e) => { eprintln!("I/O error: {e}"); break; }
Ok(_) => { /* safe to parse */ }
} Try / catch
// Rust equivalent of try-catch for io::Result
match io::stdin().read_line(&mut guess) {
Ok(n) if n > 0 => { /* have data, parse it */ }
Ok(0) => break, // EOF: exit the guess loop
Err(e) => {
eprintln!("Failed to read from stdin: {e}");
break; // error: exit the guess loop
}
} Prevention
- Never call .expect() or .unwrap() on read_line — always match the Result.
- Always handle Ok(0) explicitly: EOF is distinct from error and is the most common non-interactive scenario.
- Test interactive programs by piping input and verifying graceful exit on exhaustion.
- Consider std::process::exit(0) for clean EOF shutdown instead of breaking from nested loops.
When it happens
Trigger: Piping a limited number of lines into the game (e.g. echo "50\n" | cargo run) and the pipe source closes while the while-guess loop is still iterating. A process supervisor or container that does not allocate a real stdin file descriptor. A terminal driver or SSH session drop mid-read.
Common situations: Running in CI or scripts with piped input that has fewer lines than MAX_GUESSES. Testing the game non-interactively with a here-string. Running under Docker or systemd without -it or StandardInput=tty.
Related errors
AI-assisted analysis of coding-horror/basic-computer-games@5301155192 (2026-08-13).
Data as JSON: /api/errors/3742179e1a6cf286.
Report an issue: GitHub.