{"record":{"id":"94946ae0598a79a9","repo":"coding-horror/basic-computer-games","slug":"failed-to-read-input","errorCode":null,"errorMessage":"failed to read input","messagePattern":"failed to read input","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"22_Change/rust/src/main.rs","lineNumber":132,"sourceCode":"}\n\n/**\n * get number of money from user input\n */\nfn get_dollar_value_in_cents_from_user(prompt:&str) -> i16 {\n    let mut value:i16;\n    //input loop\n    loop {\n        //data\n        let mut raw_input = String::new();\n\n        //print prompt\n        print!(\"{}\",prompt);\n        //flush std out // allows prompt to be on same line as input\n        stdout().flush().expect(\"failed to flush\");\n\n        //get input\n        io::stdin().read_line(&mut raw_input).expect(\"failed to read input\");\n        //filter out characters that aren't numbers or '.'\n        let mut no_prior_periods = true;\n        raw_input = raw_input.chars().filter(|c| {\n            if c.eq_ignore_ascii_case(&'.') && no_prior_periods {\n                no_prior_periods = false;\n                true\n            } else {\n                c.is_ascii_digit()\n            }\n        }).collect();\n\n        //should only be (at most) 1 .\n        if !raw_input.contains(\".\") { raw_input += \".00\";} //if there are none, add one\n\n        //ensure there are at least 2 trailing digits\n        if raw_input[raw_input.find('.').unwrap_or(raw_input.len())..].len() <= 2 { //if a slice of the string from the . onwards is less than or equal to 2, add two 0's to the end\n            raw_input += \"00\"\n        }","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/22_Change/rust/src/main.rs#L114-L150","documentation":"A panic via .expect(\"failed to read input\") on io::stdin().read_line() in get_dollar_value_in_cents_from_user() of the Change Rust port, used to read a dollar amount. read_line returns Err only on I/O-level failure (closed stdin, EOF, broken pipe); non-numeric characters are filtered out afterward (the code keeps only digits and the first '.'). The expect thus aborts only when stdin itself cannot be read.","triggerScenarios":"stdin closed or exhausted before the amount prompt is answered; redirected input that ends; broken pipe to stdin; `< /dev/null`.","commonSituations":"Piped input fixtures with too few lines; headless/CI runs with no TTY; a feeder script closing stdin after a fixed count.","solutions":["Provide a numeric line for each amount prompt in piped input.","Run interactively so stdin remains open.","Swap .expect for a match that returns a default or exits cleanly on read error."],"exampleFix":"// before\nio::stdin().read_line(&mut raw_input).expect(\"failed to read input\");\n\n// after\nif io::stdin().read_line(&mut raw_input).is_err() {\n    println!(\"\\nUnable to read input. Exiting.\");\n    std::process::exit(1);\n}","handlingStrategy":"try-catch","validationCode":"// Ensure stdin is open / has lines before prompting; provide a numeric line per amount prompt when piping.","typeGuard":null,"tryCatchPattern":"// Replace .expect with a match\nmatch io::stdin().read_line(&mut raw_input) {\n    Ok(_) => { /* filter digits, parse cents */ }\n    Err(_) | Ok(0) => { println!(\"Input unavailable. Exiting.\"); std::process::exit(1); }\n}","preventionTips":["Match read_line's Result; don't .expect on user input.","Provide a numeric line per amount prompt in piped runs.","Exit cleanly on EOF (Ok(0))."],"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"}