{"record":{"id":"c60f1c4d620db0d6","repo":"coding-horror/basic-computer-games","slug":"input-error","errorCode":null,"errorMessage":"input error","messagePattern":"input error","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"53_King/rust/src/main.rs","lineNumber":13,"sourceCode":"#![forbid(unsafe_code)]\n\nuse fastrand::Rng;\nuse std::io;\nuse std::io::{stdin, stdout, BufRead, Write};\n\n// global variable `N5` in the original game\nconst TERM_LENGTH: u32 = 8;\n\nfn main() {\n    let mut rng = Rng::new();\n    let mut input = stdin().lock();\n    let mut state = intro(&mut input, &mut rng).expect(\"input error\");\n\n    loop {\n        let land_price = 95 + rng.u32(0..10);\n        let plant_price = 10 + rng.u32(0..5);\n        print_state(&state, land_price, plant_price);\n        state = match next_round(&mut input, &mut rng, &state, land_price, plant_price)\n            .expect(\"input error\")\n        {\n            RoundEnd::Next(s) => s,\n            RoundEnd::GameOver(msg) => {\n                println!(\"{}\", msg);\n                return;\n            }\n        }\n    }\n}\n\n// The game is round based (one round per in-game year).","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/53_King/rust/src/main.rs#L1-L31","documentation":"In 53_King, main calls intro(&mut input, &mut rng).expect(\"input error\") where intro returns io::Result<State>. Unlike the other errors, this .expect() wraps an entire function, not a single read_line. The panic can originate from any I/O failure inside intro: stdout().flush()?, input.read_line()?, or any read_int/read_and_verify_int call that propagates an error via ?. The single message 'input error' obscures which specific I/O operation failed.","triggerScenarios":"Any I/O failure during the intro sequence: flushing the 'DO YOU WANT INSTRUCTIONS?' prompt fails (broken pipe), reading the instruction/again/custom-state choice hits EOF, or reading numeric state values (money, countrymen, workers, land) fails because stdin is exhausted.","commonSituations":"Piped input that ends during the intro sequence, pressing Ctrl+D while answering intro questions, or CI tests that don't cover the 'again' (resume savegame) branch which requires many more input lines.","solutions":["Replace .expect() with match to print a user-friendly message on Err before exiting","Use if let Err(e) = intro(...) to log the actual io::Error for debugging, since the generic 'input error' message hides the root cause","Wrap the main function body in a helper that returns Result<(), Box<dyn Error>> and use ? throughout, then print the error in main"],"exampleFix":"// before\nlet mut state = intro(&mut input, &mut rng).expect(\"input error\");\n\n// after\nlet mut state = match intro(&mut input, &mut rng) {\n    Ok(s) => s,\n    Err(e) => {\n        eprintln!(\"Failed to read input during intro: {}\", e);\n        return;\n    }\n};","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let mut state = match intro(&mut input, &mut rng) {\n    Ok(s) => s,\n    Err(e) => {\n        eprintln!(\"Input error during intro: {}\", e);\n        return;\n    }\n};","preventionTips":["When calling functions that return io::Result, use match to print the actual error — generic .expect('input error') messages hide which specific I/O operation failed","Do not use .expect() on functions that perform multiple I/O operations; the error message cannot identify the failing step","Ensure intro sequences that ask many sequential questions are tested with piped input that provides all required lines"],"tags":["rust","stdin","read-line","panic","expect","io-error","eof","interactive","result-propagation","cli"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}