{"record":{"id":"7e79bdee5d3fad01","repo":"coding-horror/basic-computer-games","slug":"cannot-read-input-7e79bd","errorCode":null,"errorMessage":"CANNOT READ INPUT!","messagePattern":"CANNOT READ INPUT!","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"94_War/rust/src/main.rs","lineNumber":148,"sourceCode":"        The computer gives you and it a 'card'. The higher card\n        (numerically) wins. The game ends when you choose not to\n        continue or when you have finished the pack.\\n\n        \");\n    }\n}\n\n/**\n * returns true if user input starts with y or Y,\n * false otherwise\n */\nfn get_yes_no_from_user_input(prompt: &str) -> bool {\n    let mut raw_input = String::new(); // temporary variable for user input that can be parsed later\n\n    //print prompt\n    println!(\"{}\", prompt);\n    //read user input from standard input, and store it to raw_input\n    //raw_input.clear(); //clear input\n    io::stdin().read_line(&mut raw_input).expect( \"CANNOT READ INPUT!\");\n\n    //from input, try to read a valid character\n    if let Some(i) = raw_input.trim().chars().nth(0) {\n        if i == 'y' || i == 'Y' {\n            return true;\n        }\n    }\n    //default case\n    return false;\n}\n","sourceCodeStart":130,"sourceCodeEnd":159,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/94_War/rust/src/main.rs#L130-L159","documentation":"The get_yes_no_from_user_input helper for the War card game calls read_line().expect(\"CANNOT READ INPUT!\") to read a single yes/no answer. The panic fires on io::Error only. On EOF (Ok(0)) the buffer is empty, the trimmed string has no first char, and the function falls through to return false — meaning the game silently treats disconnected stdin as 'no' and exits without error. This is a silent-data-loss behavior, not a crash, but the expect panic itself is what is logged.","triggerScenarios":"A broken stdin pipe during any of the three prompt points (continue, play again, directions). A terminal device error. Running under a supervisor that revokes stdin.","commonSituations":"Piped input from a file that closes between turns. Non-interactive execution where stdin is /dev/null (Ok(0) path, silent 'no'). CI or Docker without -it.","solutions":["Replace .expect() with a match; on Ok(0) log 'input closed' and return false; on Err(e) eprintln and return false or process::exit(1).","Distinguish EOF (graceful exit, return false) from I/O error (log and exit) so the silent 'no' behavior becomes an explicit decision.","For automated testing, ensure every yes/no prompt in the game flow receives a line.","Wrap read_line in a helper that returns Option<String> (None on EOF/error) to centralize the logic for all three call sites."],"exampleFix":"// before\nio::stdin().read_line(&mut raw_input).expect(\"CANNOT READ INPUT!\");\n\n// after\nmatch io::stdin().read_line(&mut raw_input) {\n    Ok(0) => return false, // EOF: treat as \"no\"\n    Ok(_) => {}\n    Err(e) => {\n        eprintln!(\"Input error: {e}\");\n        return false;\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Distinguish EOF (graceful false) from error (logged false)\nfn get_yes_no_from_user_input(prompt: &str) -> bool {\n    let mut raw_input = String::new();\n    println!(\"{}\", prompt);\n    match io::stdin().read_line(&mut raw_input) {\n        Ok(0) => return false,  // EOF: treat as \"no\"\n        Err(e) => {\n            eprintln!(\"Input error: {e}\");\n            return false;\n        }\n        Ok(_) => {}\n    }\n    raw_input.trim().starts_with(['y', 'Y'])\n}","typeGuard":null,"tryCatchPattern":"// Centralized yes/no reader — replace the expect-based version\nmatch io::stdin().read_line(&mut raw_input) {\n    Ok(n) if n > 0 => {\n        raw_input.trim().chars().next()\n            .map(|c| c == 'y' || c == 'Y')\n            .unwrap_or(false)\n    }\n    _ => false,  // EOF or error: default to \"no\"\n}","preventionTips":["Centralize stdin reading in one helper so EOF/error handling is consistent across all three call sites.","Use .starts_with(['y','Y']) instead of chars().nth(0) for clarity and zero-allocation.","Test the game with piped input that closes mid-session to verify graceful exit.","Distinguish 'user chose no' from 'input unavailable' in logs to aid debugging."],"tags":["rust","io","stdin","panic","yes-no","silent-eof","war"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}