{"record":{"id":"36e9b33e86344b9a","repo":"coding-horror/basic-computer-games","slug":"failed-to-get-input-36e9b3","errorCode":null,"errorMessage":"Failed to get input","messagePattern":"Failed to get input","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"82_Stars/rust_JWB/src/main.rs","lineNumber":117,"sourceCode":"=======\nuse rand::Rng;\nuse std::io;\n\nfn main() {\n    println!(\n        \"{: >39}\\n{: >57}\\n\\n\\n\",\n        \"STARS\", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    );\n    // STARS - PEOPLE'S COMPUTER CENTER, MENLO PARK, CA\n    // A IS LIMIT ON NUMBER, M IS NUMBER OF GUESSES\n    let a: u32 = 101;\n    let m: u32 = 7;\n    let mut need_instrut = String::new();\n\n    println!(\"DO YOU WANT INSTRUCTIONS?\");\n    io::stdin()\n        .read_line(&mut need_instrut)\n        .expect(\"Failed to get input\");\n\n    if need_instrut[..1].to_ascii_lowercase().eq(\"y\") {\n        println!(\"I AM THINKING OF A WHOLE NUMBER FROM 1 TO {}\", a - 1);\n        println!(\"TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I\");\n        println!(\"WILL TYPE ONE OR MORE STARS (*).  THE MORE\");\n        println!(\"STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER.\");\n        println!(\"ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)\");\n        println!(\"MEANS REALLY CLOSE!  YOU GET {} GUESSES.\\n\\n\", m);\n    }\n\n    loop {\n        println!(\"\\nOK, I AM THINKING OF A NUMBER, START GUESSING.\\n\");\n        let rand_number: i32 = rand::thread_rng().gen_range(1..a) as i32; // generates a random number between 1 and 100\n\n        // GUESSING BEGINS, HUMAN GETS M GUESSES\n        for i in 0..m {\n            let mut guess = String::new();\n            println!(\"YOUR GUESS?\");","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/82_Stars/rust_JWB/src/main.rs#L99-L135","documentation":"Same read_line().expect() pattern as the other Stars game inputs, but this call reads the initial yes/no answer to 'DO YOU WANT INSTRUCTIONS?'. The panic fires on a genuine io::Error from read_line. A secondary latent bug exists just below at line 126: need_instrut[..1] slices into the string without bounds checking, so if read_line returns Ok(0) (EOF, empty string) the slice itself panics with a separate index-out-of-bounds error before the parse logic runs.","triggerScenarios":"Piped input that closes before the first prompt is answered. Ctrl-D pressed at the 'DO YOU WANT INSTRUCTIONS?' prompt. A non-interactive environment (CI, Docker without -it) where stdin has no data at all.","commonSituations":"Running cargo run with input redirected from /dev/null or an empty file. Piping only gameplay guesses without first answering the instructions prompt. SSH session dropping before the first keystroke.","solutions":["Replace .expect() with a match that defaults to 'no instructions' on both Ok(0) and Err, since skipping instructions is a safe fallback.","Replace the unguarded slice need_instrut[..1] with need_instrut.trim().to_ascii_lowercase().starts_with('y') to avoid the separate index-out-of-bounds panic on empty input.","If you must index, use need_instrut.get(..1) which returns Option and handle None gracefully.","For CI, prepend a 'n\\n' or 'y\\n' line at the start of piped input to satisfy this prompt before gameplay lines."],"exampleFix":"// before\nio::stdin()\n    .read_line(&mut need_instrut)\n    .expect(\"Failed to get input\");\n\nif need_instrut[..1].to_ascii_lowercase().eq(\"y\") {\n\n// after\nlet want = match io::stdin().read_line(&mut need_instrut) {\n    Ok(0) | Err(_) => false,\n    Ok(_) => need_instrut.trim().to_ascii_lowercase().starts_with('y'),\n};\nif want {","handlingStrategy":"try-catch","validationCode":"// Validate read_line result AND guard the slice access\nlet want_instr = match io::stdin().read_line(&mut need_instrut) {\n    Ok(0) | Err(_) => false,\n    Ok(_) => need_instrut.trim().to_ascii_lowercase().starts_with('y'),\n};\nif want_instr { /* print instructions */ }","typeGuard":null,"tryCatchPattern":"// Handle I/O error, EOF, AND empty-string slice safely\nmatch io::stdin().read_line(&mut need_instrut) {\n    Ok(0) => { /* EOF: default to no instructions */ }\n    Err(e) => eprintln!(\"Input error: {e}\"),\n    Ok(_) => {\n        // Safe alternative to need_instrut[..1] which panics on empty string\n        if need_instrut.trim().to_ascii_lowercase().starts_with('y') {\n            // print instructions\n        }\n    }\n}","preventionTips":["Never use [..1] or [0] on a String without checking length — use .starts_with() or .chars().next() instead.","Match read_line's Result and treat EOF (Ok(0)) as a distinct case from Err.","Default to the safe branch (skip instructions) when input is unavailable.","Test with empty input (echo -n '' | cargo run) to catch slice-bounds panics."],"tags":["rust","io","stdin","panic","indexing","slice-bounds"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}