{"record":{"id":"26b9aadd3d144074","repo":"coding-horror/basic-computer-games","slug":"failed-to-read-line-26b9aa","errorCode":null,"errorMessage":"Failed to read line.","messagePattern":"Failed to read line\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"64_Nicomachus/rust/src/main.rs","lineNumber":68,"sourceCode":"        let input = read_line().trim().to_uppercase();\n        let input = input.as_str();\n\n        if input == \"Y\" || input == \"YES\" {\n            return true;\n        } else if input == \"N\" || input == \"NO\" {\n            return false;\n        } else {\n            println!(\"Please input either (Y)es or (N)o.\")\n        }\n    }\n}\n\nfn read_line() -> String {\n    let mut input = String::new();\n\n    io::stdin()\n        .read_line(&mut input)\n        .expect(\"Failed to read line.\");\n\n    input\n}\n","sourceCodeStart":50,"sourceCodeEnd":72,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/64_Nicomachus/rust/src/main.rs#L50-L72","documentation":"This panic is triggered by `.expect(\"Failed to read line.\")` on `io::stdin().read_line()` inside the `read_line()` utility function in Nicomachus (line 68). This helper returns `String`, not `Result`, so callers have no way to detect or handle a read failure — the panic is the only failure mode.","triggerScenarios":"Stdin returns `Err` or EOF. The function is called from every yes/no prompt in the game (the `yes_or_no` function at the top of the file uses it), so the crash can occur at any prompt. An empty line read (just Enter) returns `Ok` and does not trigger this panic.","commonSituations":"Non-interactive execution without stdin. Piped input file exhausted. Terminal closed mid-session. Running in a sandboxed environment with no TTY.","solutions":["Change `read_line()` to return `Option<String>`, mapping EOF and errors to `None`.","Callers should check for `None` and exit the game gracefully.","Provide complete input fixtures for non-interactive testing."],"exampleFix":"// before\nfn read_line() -> String {\n    let mut input = String::new();\n    io::stdin().read_line(&mut input).expect(\"Failed to read line.\");\n    input\n}\n\n// after\nfn read_line() -> Option<String> {\n    let mut input = String::new();\n    match io::stdin().read_line(&mut input) {\n        Ok(0) | Err(_) => None,\n        Ok(_) => Some(input),\n    }\n}","handlingStrategy":"try-catch","validationCode":"use std::io::IsTerminal;\nif !io::stdin().is_terminal() {\n    // Consider reading from a file or argument instead\n}","typeGuard":"fn read_line() -> Option<String> {\n    let mut input = String::new();\n    match io::stdin().read_line(&mut input) {\n        Ok(0) | Err(_) => None,\n        Ok(_) => Some(input),\n    }\n}","tryCatchPattern":"match io::stdin().read_line(&mut input) {\n    Ok(0) | Err(_) => { println!(\"\\nInput ended.\"); std::process::exit(0); }\n    Ok(_) => { /* return input */ }\n}","preventionTips":["Return Option from utility read functions so all callers can detect EOF.","Handle EOF at the top level of the game and exit cleanly.","Avoid .expect() in any function meant to be reused across input sites."],"tags":["rust","stdin","io","panic","expect","utility-function","cli-game"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}