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

  1. Replace .expect() with ? and change the return type to Result<usize, Box<dyn Error>> to propagate both I/O and parse errors uniformly
  2. 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)
  3. 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 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


AI-assisted analysis of coding-horror/basic-computer-games@5301155192 (2026-08-13). Data as JSON: /api/errors/be8dce55403f5454. Report an issue: GitHub.