{"record":{"id":"8469531ec51a871e","repo":"coding-horror/basic-computer-games","slug":"failed-to-read-line-846953","errorCode":null,"errorMessage":"Failed to read line","messagePattern":"Failed to read line","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"35_Even_Wins/rust/src/main.rs","lineNumber":107,"sourceCode":"            println!(\"You are the winner! Congratulations!\");\n        } else {\n            println!(\"The computer wins: all hail mighty silicon!\");\n        }\n\n        println!(\"\");\n    }\n}\n\nfn human_play(game: &mut Game) {\n    println!(\"It's your turn!\");\n    loop {\n        let max_take = game.get_max_take();\n        println!(\"Marbles to take? ({} - {}) --> \", game.min_take, max_take);\n\n        let mut num = String::new();\n        io::stdin()\n            .read_line(&mut num)\n            .expect(\"Failed to read line\");\n\n        let _: u32 = match num.trim().to_uppercase().parse() {\n            Ok(num) => {\n                if game.take(num) {\n                    println!(\"Okay, taking {} marble ...\", num);\n                    break;\n                };\n                println!(\"\");\n                continue;\n            }\n            _ => {\n                println!(\"Please enter a whole number from 1 to 4\");\n                println!(\"\");\n                continue;\n            }\n        };\n    }\n}","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/35_Even_Wins/rust/src/main.rs#L89-L125","documentation":"In 35_Even_Wins, human_play reads how many marbles the human wants to take via io::stdin().read_line(&mut num).expect(\"Failed to read line\"). The input is parsed as u32 inside a match that already handles parse failures by printing an error and continuing the loop. The .expect() guards only the I/O layer: a stdin EOF or read failure panics, while invalid numbers are handled gracefully.","triggerScenarios":"The human player's turn arrives and stdin is at EOF (piped input exhausted, Ctrl+D pressed), or the read syscall fails. The game loop would handle a bad number, but cannot recover from a missing input.","commonSituations":"Automated testing of the Even_Wins game where the input script runs out during a human turn, or a user closing the terminal when prompted for a marble count.","solutions":["Replace .expect() with .unwrap_or_default() — an empty string will fail the u32 parse, triggering the existing 'Please enter a whole number' retry","Use match on read_line's Result to break out of the loop and end the game on EOF","Return early from human_play on I/O error, signaling the game to end"],"exampleFix":"// before\nlet mut num = String::new();\nio::stdin()\n    .read_line(&mut num)\n    .expect(\"Failed to read line\");\n\nlet _: u32 = match num.trim().to_uppercase().parse() {\n\n// after\nlet mut num = String::new();\nlet _ = io::stdin().read_line(&mut num);\n\nlet _: u32 = match num.trim().to_uppercase().parse() {","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"let mut num = String::new();\nlet _ = io::stdin().read_line(&mut num);\n// empty string from I/O failure falls through to parse error,\n// which the existing match handles by re-prompting","preventionTips":["When a parse-failure retry loop already exists, use let _ = read_line(...) so I/O failures degrade to parse failures and reuse the same retry path","Use unwrap_or_default() or let _ = to avoid panicking on reads that feed into existing validation loops","Ensure game-loop input reads are resilient to EOF by letting downstream validation catch empty strings"],"tags":["rust","stdin","read-line","panic","expect","io-error","eof","interactive","game-logic","cli"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}