{"record":{"id":"d9cc3d1db8b45dc4","repo":"coding-horror/basic-computer-games","slug":"something-went-wrong-getting-user-guess","errorCode":null,"errorMessage":"something went wrong getting user guess","messagePattern":"something went wrong getting user guess","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"60_Mastermind/rust/Mastermind_refactored_for_conventions/src/lib.rs","lineNumber":126,"sourceCode":"\n/// run a round with computer as code-maker\n/// returns the number of turns it takes the human to guess the secret code\nfn play_round_computer_codemaker(config: &Config) -> Option<usize> {\n    //DATA\n    let mut rng = thread_rng();\n    let mut guesses: Vec<Code> = Vec::new();\n    let secret: Code;\n\n    //generate secret\n    secret = Code::new_from_int(rng.gen_range(0..config.num_colors.pow(config.num_positions.try_into().unwrap())), config);\n\n    //round loop\n    for human_moves in 1..=config.num_guesses {\n        //get guess from user input\n        //input loop\n        let mut guess = loop {\n            //get input\n            let user_input = get_string_from_user_input(format!(\"\\nMOVE # {} GUESS: \", human_moves).as_str()).expect(\"something went wrong getting user guess\");\n\n            //parse input\n            if user_input.trim().eq_ignore_ascii_case(\"board\") { //print the board state\n                print_board(&guesses);\n                continue; //run input loop again\n            } else if user_input.trim().eq_ignore_ascii_case(\"quit\") { //quit the game\n                println!(\"QUITTER!  MY COMBINATION WAS: {}\\nGOOD BYE\", secret.as_human_readible_chars());\n                return None; //exit the game\n            } else {\n                //parse input for a code\n                match Code::new_from_string(&user_input, &config) {\n                    Ok(code) => {\n                        //ensure code is correct length\n                        if code.code.len() != config.num_positions { // if not\n                            println!(\"BAD NUMBER OF POSITIONS.\");\n                            continue; //run loop again\n                        }\n                        else {break code;}//break with the code","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/60_Mastermind/rust/Mastermind_refactored_for_conventions/src/lib.rs#L108-L144","documentation":"This panic is triggered by `.expect(\"something went wrong getting user guess\")` on `get_string_from_user_input()` in the refactored Mastermind lib (line 126). Unlike the original Mastermind, `get_string_from_user_input` *properly* returns `Result<String, Box<dyn Error>>` with the underlying I/O error embedded (`\"ERROR: CANNOT READ INPUT!: {err}\"`). The caller then defeats this design by calling `.expect()`, converting a recoverable `Err` back into a panic.","triggerScenarios":"`get_string_from_user_input` returns `Err` when `io::stdin().read_line()` fails (line 405–408 of the same file). The `.expect` at line 126 fires on any such error during the human guess loop. Because the function already provides structured error information, the crash is purely a caller-side defect.","commonSituations":"Stdin closed or I/O error during a guess. Running the library's game logic from a test or service without a live terminal. The refactored version was improved to use `Result` internally but the call sites were not updated to match.","solutions":["Propagate the error up: change `play_round_human_codebreaker` to return `Result<Option<usize>, Box<dyn Error>>` and use `?` instead of `.expect`.","Match on the `Result`, printing the embedded error message and continuing the loop or returning `None` to gracefully exit.","Refactor the call sites to match the function's `Result`-returning contract that was already implemented."],"exampleFix":"// before\nlet user_input = get_string_from_user_input(\n    format!(\"\\nMOVE # {} GUESS: \", human_moves).as_str())\n    .expect(\"something went wrong getting user guess\");\n\n// after\nlet user_input = match get_string_from_user_input(\n    format!(\"\\nMOVE # {} GUESS: \", human_moves).as_str())\n{\n    Ok(s) => s,\n    Err(e) => { eprintln!(\"{}\", e); return None; }\n};","handlingStrategy":"try-catch","validationCode":"// get_string_from_user_input already returns Result;\n// callers should not .expect() it.\n// Validate at the call site:\nif let Ok(s) = get_string_from_user_input(\"prompt\") {\n    // use s\n}","typeGuard":"// The function already returns Result<String, Box<dyn Error>>.\n// Treat it as a fallible operation, not an infallible one.","tryCatchPattern":"match get_string_from_user_input(\n    format!(\"\\nMOVE # {} GUESS: \", human_moves).as_str())\n{\n    Ok(user_input) => { /* parse user_input */ }\n    Err(e) => { eprintln!(\"{}\", e); return None; }\n}","preventionTips":["When a helper already returns Result, use ? or match — never .expect().","Audit all call sites when refactoring a function from panicking to Result-returning.","Propagate errors up to a level that can decide on graceful exit or retry."],"tags":["rust","stdin","io","panic","expect","result-ignored","refactored","mastermind"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}