coding-horror/basic-computer-games · error
~~Failed reading line!~~
Error message
~~Failed reading line!~~
What it means
In 30_Cube, a private read_line() helper calls io::stdin().read_line(...).expect("~~Failed reading line!~~") and then parses the input as usize. The function returns Result<usize, ParseIntError>, so parse failures are already handled gracefully by callers (prompt_bool and prompt_number use if let Ok(n) = read_line()). However, the I/O failure from read_line itself panics, creating an asymmetry: bad input is tolerated but missing input crashes.
Source
Thrown at 30_Cube/rust/src/util.rs:31
pub fn get_landmines() -> Vec<Position> {
let mut landmines = Vec::new();
for _ in 0..5 {
let mut m = get_random_position();
while landmines.contains(&m) {
m = get_random_position();
}
landmines.push(m);
}
landmines
}
fn read_line() -> Result<usize, ParseIntError> {
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect("~~Failed reading line!~~");
input.trim().parse::<usize>()
}
pub fn prompt_bool(msg: &str) -> bool {
loop {
println!("{}", msg);
if let Ok(n) = read_line() {
if n == 1 {
return true;
} else if n == 0 {
return false;
}
}
println!("ENTER YES--1 OR NO--0\n");
}
}
View on GitHub (pinned to 5301155192)
Solutions
- Replace .expect() with ? and change the return type to Result<usize, Box<dyn Error>> to propagate both I/O and parse errors uniformly
- Use .unwrap_or(0) so that an I/O failure produces a parse-failing value (0 won't match 1 or 0 in prompt_bool, so the existing retry loop handles it)
- Change read_line to return Option<usize> and have callers break the loop on None
Example fix
// before
fn read_line() -> Result<usize, ParseIntError> {
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect("~~Failed reading line!~~");
input.trim().parse::<usize>()
}
// after
fn read_line() -> Option<usize> {
let mut input = String::new();
if std::io::stdin().read_line(&mut input).ok()? == 0 {
return None;
}
input.trim().parse::<usize>().ok()
} Defensive patterns
Strategy: try-catch
Try / catch
fn read_line() -> Option<usize> {
let mut input = String::new();
if std::io::stdin().read_line(&mut input).ok()? == 0 {
return None;
}
input.trim().parse::<usize>().ok()
} Prevention
- When a function returns Result<T, ParseIntError> for parse failures, do not panic on I/O failures — convert I/O errors to the same error path so callers handle them uniformly
- Use .ok()? to flatten both I/O and parse errors into Option in helper functions that already have graceful callers
- Ensure the error handling strategy is symmetric: if parse failures are tolerated, I/O failures should be too
When it happens
Trigger: The Cube game prompts for a numeric input (boolean 1/0, or a number) and stdin returns Err or EOF. Since callers already loop on parse failures, the only way to reach the panic is an actual I/O-level failure.
Common situations: Piping input that ends before the player finishes navigating the cube, pressing Ctrl+D, or running in a non-interactive test where stdin is exhausted.
Related errors
- Error reading line.
- Failed to get Input
- Failed to read input.
- Error reading from stdin
- Failed to read line
AI-assisted analysis of coding-horror/basic-computer-games@5301155192 (2026-08-13).
Data as JSON: /api/errors/be8dce55403f5454.
Report an issue: GitHub.