coding-horror/basic-computer-games · error

Failed to read the line

Error message

Failed to read the line

What it means

Inside the ask_question function for the Synonym game, read_line().expect("Failed to read the line") reads the player's answer inside an infinite loop. The panic fires only on io::Error from read_line, not on EOF. On EOF (Ok(0)) the trimmed answer is empty, which is neither 'HELP' nor a match in this_question, so the loop repeats indefinitely — printing the prompt and reading EOF forever in a busy-spin.

Source

Thrown at 85_Synonym/rust/src/main.rs:35

    println!("LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME MEANING.");
    println!("I CHOOSE A WORD -- YOU TYPE A SYNONYM.");
    println!("IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'");
    println!("AND I WILL TELL YOU A SYNONYM.\n");
}

fn ask_question(mut this_question: Vec<&str>) {
    let right_words = ["RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK"];

    // use the first one in the main question
    let base_word = this_question.remove(0);

    loop {
        print!("     WHAT IS A SYNONYM OF {base_word}? ");
        io::stdout().flush().unwrap();
        let mut answer: String = String::new();
        io::stdin()
            .read_line(&mut answer)
            .expect("Failed to read the line");
        let answer = answer.trim();
        if answer == "HELP" {
            // remove one random from the answers and show it
            let random_index = thread_rng().gen_range(0..this_question.len());
            println!(
                "**** A SYNONYM OF {base_word} IS {}.",
                this_question.remove(random_index)
            );
        } else if this_question.contains(&answer) {
            println!("{}", right_words.choose(&mut rand::thread_rng()).unwrap());
            break;
        }
    }
}

fn main() {
    const PAGE_WIDTH: usize = 64;

View on GitHub (pinned to 5301155192)

Solutions

  1. Match on read_line's Result; on Ok(0) break the loop or call process::exit(0) since the user has disconnected.
  2. On Err(e), print the error and break the outer quiz loop gracefully.
  3. Add a maximum-retry or abandon-on-EOF flag so the quiz terminates cleanly when input is exhausted.
  4. For testing, pipe enough synonym answers to satisfy every question in the quiz.

Example fix

// before
io::stdin()
    .read_line(&mut answer)
    .expect("Failed to read the line");

// after
match io::stdin().read_line(&mut answer) {
    Ok(0) => { println!("\nGoodbye!"); return; }
    Ok(_) => {}
    Err(e) => { eprintln!("Input error: {e}"); return; }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Break the quiz loop on EOF or error instead of spinning forever
match io::stdin().read_line(&mut answer) {
    Ok(0) => { println!("Goodbye!"); return; }
    Err(e) => { eprintln!("Input error: {e}"); return; }
    Ok(_) => { /* safe to trim and check answer */ }
}

Try / catch

// Inside the loop{...} of ask_question
match io::stdin().read_line(&mut answer) {
    Ok(n) if n > 0 => { /* have input, proceed with trim/check */ }
    Ok(0) => break,  // EOF: exit quiz loop
    Err(e) => {
        eprintln!("{e}");
        break;
    }
}

Prevention

When it happens

Trigger: Piped input that runs out while the quiz loop is active. A dropped SSH or terminal session mid-quiz. A broken stdin pipe from a parent process that terminated early.

Common situations: Automated quiz testing with limited piped input. Running the synonym quiz under a script or CI pipeline. Terminal connection lost during interactive play.

Related errors


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