{"record":{"id":"e25f3953da10086a","repo":"coding-horror/basic-computer-games","slug":"failed-to-read-line-e25f39","errorCode":null,"errorMessage":"Failed to read line.","messagePattern":"Failed to read line\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"81_Splat/rust/src/utility.rs","lineNumber":22,"sourceCode":"\nconst DEATH_MESSAGES: [&str; 10] = [\n    \"REQUIESCAT IN PACE.\",\n    \"MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.\",\n    \"REST IN PEACE.\",\n    \"SON-OF-A-GUN.\",\n    \"#$%&&%!$\",\n    \"A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.\",\n    \"HMMM. SHOULD HAVE PICKED A SHORTER TIME.\",\n    \"MUTTER. MUTTER. MUTTER.\",\n    \"PUSHING UP DAISIES.\",\n    \"EASY COME, EASY GO.\",\n];\n\npub fn read_line() -> String {\n    let mut input = String::new();\n    io::stdin()\n        .read_line(&mut input)\n        .expect(\"Failed to read line.\");\n    input.trim().to_uppercase()\n}\n\npub fn prompt_bool(msg: &str, template: bool) -> bool {\n    if template {\n        println!(\"{} (YES OR NO)?\", msg);\n    } else {\n        println!(\"{}\", msg);\n    }\n\n    loop {\n        let response = read_line();\n\n        match response.as_str() {\n            \"YES\" => return true,\n            \"NO\" => return false,\n            _ => println!(\"PLEASE ENTER YES OR NO.\"),\n        }","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/81_Splat/rust/src/utility.rs#L4-L40","documentation":"This panic is triggered by `.expect(\"Failed to read line.\")` on `io::stdin().read_line()` inside Splat's `read_line()` utility function in `utility.rs` (line 22). This function trims and uppercases the input before returning. Because it returns `String` (not `Result`), there is no caller-side error recovery — the `.expect` is the sole failure path. The function is used by `prompt_bool` and other game input routines throughout Splat.","triggerScenarios":"Stdin returns `Err` or EOF. The function is the primary input path for the entire game, so a failure here crashes Splat at any user prompt. The `to_uppercase()` conversion happens after `read_line` succeeds, so encoding issues do not trigger this panic.","commonSituations":"Non-interactive execution. Piped input that ends before the game session completes. Terminal disconnection. Running under CI or a service manager without a TTY.","solutions":["Change `read_line()` to return `Option<String>`, mapping EOF and errors to `None`.","Callers should check `None` and exit the game gracefully or retry.","Provide complete input fixtures for non-interactive runs."],"exampleFix":"// before\npub fn read_line() -> String {\n    let mut input = String::new();\n    io::stdin().read_line(&mut input).expect(\"Failed to read line.\");\n    input.trim().to_uppercase()\n}\n\n// after\npub 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.trim().to_uppercase()),\n    }\n}","handlingStrategy":"try-catch","validationCode":"use std::io::IsTerminal;\nif !io::stdin().is_terminal() {\n    eprintln!(\"Warning: non-interactive stdin.\");\n}","typeGuard":"pub 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.trim().to_uppercase()),\n    }\n}","tryCatchPattern":"match io::stdin().read_line(&mut input) {\n    Ok(0) => { println!(\"\\nInput closed.\"); std::process::exit(0); }\n    Ok(_) => { /* proceed */ }\n    Err(_) => { println!(\"Read error.\"); }\n}","preventionTips":["Return Option from shared read_line utilities so all callers can handle EOF.","Centralize stdin error handling in one safe helper.","Test Splat with piped input that covers all prompts."],"tags":["rust","stdin","io","panic","expect","utility-function","cli-game","splat"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}