coding-horror/basic-computer-games · error
**Failed to read input**
Error message
**Failed to read input**
What it means
This panic is triggered by `.expect("**Failed to read input**")` on `io::stdin().read_line()` inside the `prompt()` function in Queen's `util.rs` (line 19). This function is the universal input handler, returning a `PromptResult` enum (`Numeric`, `YesNo`, etc.) for both numeric and text input. The `.expect` converts any I/O-level stdin failure into a crash before the enum-dispatch logic runs.
Source
Thrown at 72_Queen/rust/src/util.rs:19
use std::io;
pub enum PromptResult {
Normal(String),
YesNo(bool),
Numeric(i32),
}
pub fn prompt(is_numeric: Option<bool>, msg: &str) -> PromptResult {
use PromptResult::*;
println!("{msg}");
loop {
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("**Failed to read input**");
if let Some(is_numeric) = is_numeric {
let input = input.trim();
if is_numeric {
if let Ok(n) = input.parse::<i32>() {
return Numeric(n);
}
println!("PLEASE ENTER A VALID 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."),
}
}
} else {
return Normal(input);View on GitHub (pinned to 5301155192)
Solutions
- Add a `Cancelled` or `Failed` variant to `PromptResult` and return it on `Ok(0)` or `Err` instead of panicking.
- Change the function to return `Option<PromptResult>` so callers can detect EOF and exit.
- For non-interactive use, provide complete input covering every `prompt()` call the game makes.
Example fix
// before
io::stdin().read_line(&mut input).expect("**Failed to read input**");
// after
let bytes = io::stdin().read_line(&mut input);
match bytes {
Ok(0) | Err(_) => {
println!("\nInput closed.");
std::process::exit(0);
}
Ok(_) => {}
} Defensive patterns
Strategy: try-catch
Validate before calling
use std::io::IsTerminal;
if !io::stdin().is_terminal() {
eprintln!("Warning: non-interactive stdin.");
} Type guard
pub fn prompt(is_numeric: Option<bool>, msg: &str) -> Option<PromptResult> {
// ...
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(0) | Err(_) => return None,
Ok(_) => { /* parse and return PromptResult */ }
}
} Try / catch
match io::stdin().read_line(&mut input) {
Ok(0) => { println!("\nInput closed."); std::process::exit(0); }
Ok(_) => { /* dispatch to Numeric/YesNo */ }
Err(e) => { eprintln!("{}", e); }
} Prevention
- Add a Cancelled/Failed variant to the PromptResult enum for I/O errors.
- Never .expect() on stdin in a function that returns an enum — add a failure variant instead.
- Test with piped input that covers every prompt call in the game.
When it happens
Trigger: `read_line` returns `Err` or EOF. The function's internal validation (`input.parse::<i32>()`, uppercase matching for YES/NO) happens *after* `read_line` succeeds, so invalid *content* never reaches the `.expect`. Only stream-level failures trigger it.
Common situations: Non-interactive execution. Piped input runs out mid-game. Terminal disconnection. The game is launched from a context (GUI app, IDE run config) without a wired-up stdin.
Related errors
AI-assisted analysis of coding-horror/basic-computer-games@5301155192 (2026-08-13).
Data as JSON: /api/errors/2249f7acf13b50f4.
Report an issue: GitHub.