coding-horror/basic-computer-games · error
Failed to read line.
Error message
Failed to read line.
What it means
This is the central input utility for Tower of Hanoi: a reusable prompt() function that loops until valid input is received, then returns a PromptResult enum (Number or YesNo). The .expect("Failed to read line.") panics on io::Error. Critically, on EOF (Ok(0)) the function does NOT panic — empty input never matches a valid i32 parse or yes/no arm, so it prints the re-prompt and loops. Because EOF is sticky on stdin, this creates an infinite busy-loop that floods stdout with the prompt message forever. No caller catches the panic because PromptResult has no error variant.
Source
Thrown at 90_Tower/rust/src/util.rs:17
use std::io;
pub enum PromptResult {
Number(i32),
YesNo(bool),
}
pub fn prompt(numeric: bool, msg: &str) -> PromptResult {
use PromptResult::*;
loop {
println!("{}", msg);
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("Failed to read line.");
let input = input.trim().to_string();
if numeric {
if let Ok(n) = input.parse::<i32>() {
return Number(n);
}
println!("PLEASE ENTER A NUMBER.")
} else {
match input.to_uppercase().as_str() {
"YES" | "Y" => return YesNo(true),
"NO" | "N" => return YesNo(false),
_ => println!("PLEASE ENTER (Y)ES OR (N)O."),
}
}
}
}View on GitHub (pinned to 5301155192)
Solutions
- Match on read_line; on Ok(0) (EOF) call std::process::exit(0) or return a sentinel to end the infinite loop — this is the most impactful fix since the hang is worse than the panic.
- Add a None or Eof variant to PromptResult so callers can react to input exhaustion instead of hanging or crashing.
- On Err(e), eprintln the error and process::exit(1) for a clean shutdown with a diagnostic.
- For testing, ensure piped input has a line for every prompt the game will issue across all turns.
Example fix
// before
io::stdin()
.read_line(&mut input)
.expect("Failed to read line.");
// after
match io::stdin().read_line(&mut input) {
Ok(0) => std::process::exit(0),
Ok(_) => {}
Err(e) => {
eprintln!("Input error: {e}");
std::process::exit(1);
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Critical: handle BOTH Err (panic) and Ok(0) (infinite loop)
match io::stdin().read_line(&mut input) {
Ok(0) => std::process::exit(0), // EOF: stop the infinite re-prompt
Ok(_) => { /* safe to trim and parse */ }
Err(e) => {
eprintln!("Input error: {e}");
std::process::exit(1);
}
} Type guard
// If refactoring PromptResult to carry an EOF variant:
// pub enum PromptResult {
// Number(i32),
// YesNo(bool),
// Eof, // new variant for input exhaustion
// }
// Then callers can match on Eof to exit cleanly. Try / catch
// In the reusable prompt() function — must handle both failure modes
loop {
println!("{}", msg);
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(n) if n > 0 => { /* proceed with validation */ }
Ok(0) => std::process::exit(0), // EOF: prevent infinite loop
Err(e) => {
eprintln!("Input error: {e}");
std::process::exit(1); // I/O error: prevent panic
}
}
// ... rest of parsing logic ...
} Prevention
- For reusable input utilities, always handle Ok(0) — infinite loops are worse than panics for users.
- Add an Eof variant to result enums so callers can react to input exhaustion.
- Test utility functions with /dev/null stdin to verify they exit, not hang.
- Consider returning Result<PromptResult, io::Error> from utility functions so callers control error policy.
- Log before process::exit so CI logs show why the program stopped.
When it happens
Trigger: Running Tower of Hanoi non-interactively with stdin from /dev/null or an exhausted pipe — causes the infinite-loop hang rather than the panic. A broken pipe or terminal driver error — causes the panic. Any of the four call sites (get_disk_count, get_disk_to_move, ask_which_needle, play-again loop) hitting an I/O failure.
Common situations: CI test that pipes disk counts and move sequences without enough lines. Docker container without -it. Automated UI testing that closes stdin early. Script that feeds partial input and then closes.
Related errors
AI-assisted analysis of coding-horror/basic-computer-games@5301155192 (2026-08-13).
Data as JSON: /api/errors/379277bbb16b78f2.
Report an issue: GitHub.