coding-horror/basic-computer-games · error
Failed to read line.
Error message
Failed to read line.
What it means
This panic is triggered by `.expect("Failed to read line.")` on `io::stdin().read_line()` inside Splat's `read_line()` utility function in `utility.rs` (line 22). This function trims and uppercases the input before returning. Because it returns `String` (not `Result`), there is no caller-side error recovery — the `.expect` is the sole failure path. The function is used by `prompt_bool` and other game input routines throughout Splat.
Source
Thrown at 81_Splat/rust/src/utility.rs:22
const DEATH_MESSAGES: [&str; 10] = [
"REQUIESCAT IN PACE.",
"MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.",
"REST IN PEACE.",
"SON-OF-A-GUN.",
"#$%&&%!$",
"A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.",
"HMMM. SHOULD HAVE PICKED A SHORTER TIME.",
"MUTTER. MUTTER. MUTTER.",
"PUSHING UP DAISIES.",
"EASY COME, EASY GO.",
];
pub fn read_line() -> String {
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("Failed to read line.");
input.trim().to_uppercase()
}
pub fn prompt_bool(msg: &str, template: bool) -> bool {
if template {
println!("{} (YES OR NO)?", msg);
} else {
println!("{}", msg);
}
loop {
let response = read_line();
match response.as_str() {
"YES" => return true,
"NO" => return false,
_ => println!("PLEASE ENTER YES OR NO."),
}View on GitHub (pinned to 5301155192)
Solutions
- Change `read_line()` to return `Option<String>`, mapping EOF and errors to `None`.
- Callers should check `None` and exit the game gracefully or retry.
- Provide complete input fixtures for non-interactive runs.
Example fix
// before
pub fn read_line() -> String {
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read line.");
input.trim().to_uppercase()
}
// after
pub fn read_line() -> Option<String> {
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(0) | Err(_) => None,
Ok(_) => Some(input.trim().to_uppercase()),
}
} 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 read_line() -> Option<String> {
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(0) | Err(_) => None,
Ok(_) => Some(input.trim().to_uppercase()),
}
} Try / catch
match io::stdin().read_line(&mut input) {
Ok(0) => { println!("\nInput closed."); std::process::exit(0); }
Ok(_) => { /* proceed */ }
Err(_) => { println!("Read error."); }
} Prevention
- Return Option from shared read_line utilities so all callers can handle EOF.
- Centralize stdin error handling in one safe helper.
- Test Splat with piped input that covers all prompts.
When it happens
Trigger: Stdin returns `Err` or EOF. The function is the primary input path for the entire game, so a failure here crashes Splat at any user prompt. The `to_uppercase()` conversion happens after `read_line` succeeds, so encoding issues do not trigger this panic.
Common situations: Non-interactive execution. Piped input that ends before the game session completes. Terminal disconnection. Running under CI or a service manager without a TTY.
Related errors
- Failed to read line.
- Failed to read line.
- **Failed to read input**
- Failed to read the line
- No valid input
AI-assisted analysis of coding-horror/basic-computer-games@5301155192 (2026-08-13).
Data as JSON: /api/errors/e25f3953da10086a.
Report an issue: GitHub.