coding-horror/basic-computer-games · error

Failed to read the line

Error message

Failed to read the line

What it means

In 54_Letter, inside a loop of up to 999999 guesses, the game reads the player's letter guess via io::stdin().read_line(&mut guess).expect("Failed to read the line"). The guess is trimmed, uppercased, and compared to a random character A-Z. There is no parse step, so the .expect() is the only failure point — an empty or wrong letter is handled by the Ordering comparison, but a stdin I/O failure panics.

Source

Thrown at 54_Letter/rust/src/main.rs:26

        "LETTER", "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
    );
    println!("LETTER GUESSING GAME\n");
    println!("I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.");
    println!("TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES");
    println!("AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.");

    loop {
        let gen_character = rand::thread_rng().gen_range('A'..='Z'); // generates a random character between A and Z
        let gen_character = String::from(gen_character);
        println!("\nO.K., I HAVE A LETTER.  START GUESSING.");
        for i in 0..999999 {
            println!("\nWHAT IS YOUR GUESS?");

            let mut guess = String::new();

            io::stdin()
                .read_line(&mut guess)
                .expect("Failed to read the line");
            println!("{}", gen_character);
            let guess = guess.trim().to_ascii_uppercase();
            match guess.cmp(&gen_character) {
                Ordering::Less => println!("\nTOO LOW.  TRY A HIGHER LETTER."),
                Ordering::Greater => println!("\nTOO HIGH.  TRY A LOWER LETTER."),
                Ordering::Equal => {
                    println!("\nYOU GOT IT IN {} GUESSES!!", i + 1);
                    if i >= 4 {
                        println!("BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\n");
                    } else {
                        println!("{}", std::iter::repeat("💖").take(15).collect::<String>());
                        println!("GOOD JOB !!!!!");
                    }
                    break;
                }
            }
        }
        println!("\nLET'S PLAY AGAIN.....");

View on GitHub (pinned to 5301155192)

Solutions

  1. Replace .expect() with .unwrap_or_default() so I/O failure yields an empty string, which the Ordering comparison handles as a wrong guess
  2. Use match to detect Ok(0) (EOF) and break the guess loop
  3. Return early from the game on Err

Example fix

// before
let mut guess = String::new();
io::stdin()
    .read_line(&mut guess)
    .expect("Failed to read the line");
println!("{}", gen_character);

// after
let mut guess = String::new();
let _ = io::stdin().read_line(&mut guess);
println!("{}", gen_character);
Defensive patterns

Strategy: fallback

Try / catch

let mut guess = String::new();
let _ = io::stdin().read_line(&mut guess);
// empty string compares as Ordering::Less or Greater,
// which the existing match handles by re-prompting

Prevention

When it happens

Trigger: The game prompts 'WHAT IS YOUR GUESS?' and stdin returns Err or EOF. Invalid guesses (empty string, multiple characters) are handled by the comparison logic (they'll be Ordering::Less or Greater), but missing input is not.

Common situations: Piped input that runs out before the letter is guessed, pressing Ctrl+D at a guess prompt, or CI tests that provide insufficient guesses.

Related errors


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