{"record":{"id":"99acdfefa5001d65","repo":"coding-horror/basic-computer-games","slug":"failed-read-line","errorCode":null,"errorMessage":"Failed read_line","messagePattern":"Failed read_line","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"43_Hammurabi/rust/src/main.rs","lineNumber":218,"sourceCode":"            println!(\"YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\");\n            println!(\"REALLY WASN'T TOO BAD AT ALL. {haters} PEOPLE\");\n            println!(\"WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\");\n            println!(\"TRIVIAL PROBLEMS.\");\n        } else {\n            println!(\"A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND\");\n            println!(\"JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\\n\");\n        }\n        for _ in 1..10 {\n            println!();\n        }\n    }\n            \n    println!(\"\\nSO LONG FOR NOW.\\n\");\n}\n\nfn get_input() -> Option<u32> {\n    let mut input = String::new();\n    io::stdin().read_line(&mut input).expect(\"Failed read_line\");\n    match input.trim().parse() {\n        Ok(num) => Some(num),\n        Err(_) => None,\n    }\n}\n\nfn gen_random() -> u32 {\n    let r: f32 = rand::thread_rng().gen();\n    (r * 5.0 + 1.0) as u32\n}\n\nfn impossible_task() {\n    println!(\"HAMURABI:  I CANNOT DO WHAT YOU WISH.\");\n    println!(\"GET YOURSELF ANOTHER STEWARD!!!!!\");\n}\n\nfn insufficient_grain(grain: u32) {\n    println!(\"HAMURABI:  THINK AGAIN.  YOU HAVE ONLY\");","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/43_Hammurabi/rust/src/main.rs#L200-L236","documentation":"In 43_Hammurabi, get_input reads a line and parses it as u32, returning Option<u32> — Some on successful parse, None on parse failure. However, the read_line call itself uses .expect(\"Failed read_line\"), so an I/O failure (EOF, broken pipe) panics before the graceful parse-failure path can execute. This creates an asymmetry: non-numeric input returns None (handled), but missing input crashes.","triggerScenarios":"The Hammurabi game prompts for a numeric input (bushels to distribute, land to buy, etc.) and stdin is at EOF or the read fails. Non-numeric text like 'abc' correctly returns None, but EOF does not.","commonSituations":"Piped input that exhausts mid-game (Hammurabi has many sequential prompts per round), pressing Ctrl+D during a steward decision, or CI tests that don't supply all required inputs.","solutions":["Replace .expect() with .unwrap_or_default() — an empty string fails to parse as u32, so get_input returns None, which callers already handle","Use match on read_line to return None on Ok(0) (EOF) or Err","Change the function to return Result<Option<u32>, io::Error> to separate I/O errors from parse failures"],"exampleFix":"// before\nfn get_input() -> Option<u32> {\n    let mut input = String::new();\n    io::stdin().read_line(&mut input).expect(\"Failed read_line\");\n    match input.trim().parse() {\n        Ok(num) => Some(num),\n        Err(_) => None,\n    }\n}\n\n// after\nfn get_input() -> Option<u32> {\n    let mut input = String::new();\n    if io::stdin().read_line(&mut input).unwrap_or(0) == 0 {\n        return None;\n    }\n    input.trim().parse().ok()\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"fn get_input() -> Option<u32> {\n    let mut input = String::new();\n    if io::stdin().read_line(&mut input).unwrap_or(0) == 0 {\n        return None;\n    }\n    input.trim().parse().ok()\n}","preventionTips":["When a function returns Option to represent parse failures, I/O failures should also return None — not panic — so callers handle them uniformly","Use unwrap_or(0) on read_line to collapse I/O errors into an EOF signal, which then fails to parse and returns None","Ensure symmetric error handling: if non-numeric input returns None, missing input should too"],"tags":["rust","stdin","read-line","panic","expect","io-error","eof","interactive","cli","parse"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}