{"record":{"id":"2fdc5da2bd596465","repo":"coding-horror/basic-computer-games","slug":"failed-to-read-line-2fdc5d","errorCode":null,"errorMessage":"Failed to read line","messagePattern":"Failed to read line","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"09_Battle/rust/src/main.rs","lineNumber":172,"sourceCode":"}\n\nimpl fmt::Display for See {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        for row in &self.data {\n            write!(f, \"\\r\\n\")?;\n            for cell in row {\n                write!(f, \"{:2} \", cell)?;\n            }\n        }\n        write!(f, \"\\r\\n\")\n    }\n}\n\nfn input_point() -> Result<Point, ()> {\n    let mut input = String::new();\n    io::stdin()\n        .read_line(&mut input)\n        .expect(\"Failed to read line\");\n    let point_str: Vec<&str> = input.trim().split(',').collect();\n\n    if point_str.len() != 2 {\n        return Err(());\n    }\n\n    let x = point_str[0].parse::<i8>().map_err(|_| ())?;\n    let y = point_str[1].parse::<i8>().map_err(|_| ())?;\n\n    Ok(Point(x, y))\n}\n\nfn get_next_target() -> Point {\n    loop {\n        print!(\"? \");\n        let _ = io::stdout().flush();\n\n        if let Ok(p) = input_point() {","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/09_Battle/rust/src/main.rs#L154-L190","documentation":"A panic via .expect(\"Failed to read line\") on io::stdin().read_line() in input_point() of the Battle Rust port, which reads an 'x,y' coordinate for a shot. read_line errors only on I/O-level failure (closed/EOF/broken stdin); malformed coordinate text (wrong number of fields, non-numeric) is handled by returning Err(()) up to the caller. The expect thus only fires when stdin itself cannot be read.","triggerScenarios":"stdin closed or exhausted before the player enters a coordinate; running the battle game with redirected input that ends; a broken pipe to stdin.","commonSituations":"Test fixtures that stop feeding input mid-game; piping `/dev/null`; an orchestration script that closes stdin after a fixed number of lines.","solutions":["Provide a coordinate line (e.g. '3,4') for every shot prompt in piped input.","Run interactively.","Replace .expect with handling that propagates an Err or exits cleanly on read failure."],"exampleFix":"// before\nio::stdin().read_line(&mut input).expect(\"Failed to read line\");\n\n// after\nif io::stdin().read_line(&mut input).is_err() {\n    return Err(());\n}","handlingStrategy":"try-catch","validationCode":"// Return Err(()) up to the caller instead of panicking\nlet n = io::stdin().read_line(&mut input);\nif n.is_err() { return Err(()); }","typeGuard":null,"tryCatchPattern":"// input_point already returns Result<Point, ()>; propagate read failure\nlet n = io::stdin().read_line(&mut input);\nif n.is_err() { return Err(()); }","preventionTips":["Since input_point returns Result, map read errors into Err(()) instead of .expect.","Provide 'x,y' lines for every shot when piping.","Handle the Err(()) at the call site with a re-prompt."],"tags":["rust","stdin","io","panic","expect"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}