{"record":{"id":"da9eb88a482f4608","repo":"coding-horror/basic-computer-games","slug":"failed-to-read-the-line-da9eb8","errorCode":null,"errorMessage":"Failed to read the line","messagePattern":"Failed to read the line","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"57_Literature_Quiz/rust/src/main.rs","lineNumber":63,"sourceCode":"        question: &'a str,\n        choices: Vec<&'a str>,\n        answer: u8,\n        correct_response: &'a str,\n        wrong_response: &'a str,\n    }\n\n    impl Question<'_>{\n        fn ask(&self) -> bool {\n            println!(\"{}\", self.question);\n            for i in 0..4 {\n                print!(\"{}){}\", i+1, self.choices[i]);\n                if i != 3 { print!(\", \")};\n            }\n            println!(\"\");\n            let mut user_input: String = String::new();\n            io::stdin()\n                .read_line(&mut user_input)\n                .expect(\"Failed to read the line\");\n\n            if user_input.starts_with(&self.answer.to_string()) {\n                println!(\"{}\", self.correct_response);\n                true\n            } else {\n                println!(\"{}\", self.wrong_response);\n                false\n            }\n        }\n    }\n\n    let questions: Vec<Question> = vec![\n        Question{\n            question: \"IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT?\",\n            choices: vec![\"TIGGER\", \"CICERO\", \"FIGARO\", \"GUIPETTO\"],\n            answer: 3,\n            wrong_response: \"SORRY...FIGARO WAS HIS NAME.\",\n            correct_response: \"VERY GOOD!  HERE'S ANOTHER.\",","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/57_Literature_Quiz/rust/src/main.rs#L45-L81","documentation":"This panic is triggered by `.expect(\"Failed to read the line\")` on `io::stdin().read_line()` inside `Question::ask()` in the Literature Quiz game. `read_line` returns `Err` only when the underlying stdin stream encounters an I/O error or is closed/redirected to an invalid source. Because `.expect` is used instead of graceful error handling, any such failure aborts the entire process with this message.","triggerScenarios":"The program's stdin is not a readable TTY — e.g., it is launched in an environment without an attached terminal, stdin is redirected from a closed file descriptor, or an automated test harness pipes EOF (Ctrl+D) into the process. In `Question::ask()`, the call is on the hot path of every quiz question, so the first such stdin disruption panics immediately.","commonSituations":"Running the binary under CI or a service manager (systemd, Docker with no `-it`) that does not wire up stdin. Piping `/dev/null` or an empty file as input. Pressing Ctrl+D on the terminal instead of typing an answer. Embedding the quiz in a GUI wrapper that forgets to provide stdin.","solutions":["Replace `.expect(\"Failed to read the line\")` with `match` on the `Result`, printing a friendly prompt and retrying on `Err` rather than panicking.","Detect EOF specifically (0 bytes read) and exit the quiz cleanly with a goodbye message instead of crashing.","If running in CI or a non-interactive context, provide input via a piped file or `expect`-style automation so stdin never closes mid-question."],"exampleFix":"// before\nio::stdin()\n    .read_line(&mut user_input)\n    .expect(\"Failed to read the line\");\n\n// after\nmatch io::stdin().read_line(&mut user_input) {\n    Ok(0) => {\n        println!(\"\\nInput closed. Goodbye!\");\n        std::process::exit(0);\n    }\n    Ok(_) => {}\n    Err(e) => {\n        eprintln!(\"Could not read input: {}\", e);\n        std::process::exit(1);\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Check stdin availability before reading\nuse std::io::IsTerminal;\nif !io::stdin().is_terminal() && std::env::var(\"FORCE_NONINTERACTIVE\").is_err() {\n    eprintln!(\"Warning: stdin is not a terminal; input may fail.\");\n}","typeGuard":"// Rust does not use type guards; instead use Result matching\nfn safe_read_line() -> Option<String> {\n    let mut buf = String::new();\n    match io::stdin().read_line(&mut buf) {\n        Ok(0) | Err(_) => None,\n        Ok(_) => Some(buf),\n    }\n}","tryCatchPattern":"match io::stdin().read_line(&mut user_input) {\n    Ok(0) => { println!(\"Input closed.\"); std::process::exit(0); }\n    Ok(_) => { /* proceed */ }\n    Err(e) => { eprintln!(\"Read error: {}\", e); std::process::exit(1); }\n}","preventionTips":["Never use .expect() on stdin reads in interactive programs — always match on the Result.","Detect EOF (0 bytes returned) explicitly and exit cleanly rather than crashing.","When testing non-interactively, pipe input files that cover every prompt the game issues."],"tags":["rust","stdin","io","panic","expect","cli-game"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}