coding-horror/basic-computer-games · error
No valid input
Error message
No valid input
What it means
This panic is triggered by `.expect("No valid input")` on `io::stdin().read_line()` in the Love program. The message is misleading — the failure is not about input *validity* (that is handled downstream by the `input.trim()` logic) but about `read_line` returning `Err` due to an I/O-level failure reading from stdin.
Source
Thrown at 58_Love/rust/src/main.rs:63
vec![6, 6, 9, 3, 12, 6, 7, 1, 10],
vec![7, 6, 7, 3, 13, 6, 6, 2, 10],
vec![7, 6, 7, 3, 13, 14, 10],
vec![8, 6, 5, 3, 14, 6, 6, 2, 10],
vec![8, 6, 5, 3, 14, 6, 7, 1, 10],
vec![9, 6, 3, 3, 15, 6, 16, 1, 1],
vec![9, 6, 3, 3, 15, 6, 15, 2, 1],
vec![10, 6, 1, 3, 16, 6, 14, 3, 1],
vec![10, 10, 16, 6, 12, 5, 1],
vec![11, 8, 13, 27, 1],
vec![11, 8, 13, 27, 1],
vec![60],
];
const ROW_LEN: usize = 60;
show_intro();
let mut input: String = String::new();
io::stdin().read_line(&mut input).expect("No valid input");
let input = if input.len() == 1 {
"LOVE"
} else {
input.trim()
};
// repeat the answer to fill the whole line, we will show chunks of this when needed
let input = input.repeat(ROW_LEN / (input.len()) + 1);
// Now lets display the Love
print!("{}", "\n".repeat(9));
for row in data {
let mut print_or_pass = PrintOrPass::Print;
let mut current_start = 0;
for count in row {
match print_or_pass {
PrintOrPass::Print => {
print!("{}", &input[current_start..count + current_start]);
print_or_pass = PrintOrPass::Pass;
View on GitHub (pinned to 5301155192)
Solutions
- Replace `.expect()` with a `match` that distinguishes `Ok(0)` (EOF) from genuine `Err`, exiting gracefully on EOF.
- Add a pre-check or configuration option to read the word from a command-line argument or file when stdin is not interactive.
- Wrap the entire read in a retry loop with a maximum attempt count for transient I/O errors.
Example fix
// before
io::stdin().read_line(&mut input).expect("No valid input");
// after
let bytes_read = io::stdin().read_line(&mut input);
match bytes_read {
Ok(0) => { println!("No input received. Exiting."); return; }
Ok(_) => {}
Err(e) => { eprintln!("Failed to read input: {}", e); return; }
} Defensive patterns
Strategy: try-catch
Validate before calling
use std::io::IsTerminal;
if !io::stdin().is_terminal() {
// Provide input via argument or file instead
} Type guard
fn safe_read_line() -> Option<String> {
let mut buf = String::new();
match io::stdin().read_line(&mut buf) {
Ok(0) | Err(_) => None,
Ok(_) => Some(buf.trim().to_string()),
}
} Try / catch
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(0) => { println!("No input. Exiting."); return; }
Ok(_) => { /* proceed with input.trim() */ }
Err(e) => { eprintln!("{}", e); return; }
} Prevention
- Replace .expect() on read_line with Result matching in all CLI programs.
- Handle EOF as a normal exit condition, not an error.
- Guard against empty input before calling input.len()-dependent operations like repeat().
When it happens
Trigger: Stdin is unavailable, closed, or returns an I/O error before any line is read. This happens before the program reaches the `input.repeat(ROW_LEN / input.len() + 1)` line, so the panic preempts the separate divide-by-zero risk on empty input. Common when the process inherits no stdin handle.
Common situations: Running inside Docker/CI without `-it` flags. Launching from a desktop launcher or IDE run configuration that does not allocate a terminal. Redirecting stdin from a broken pipe or a file that triggers an I/O error.
Related errors
AI-assisted analysis of coding-horror/basic-computer-games@5301155192 (2026-08-13).
Data as JSON: /api/errors/ab9aee8fd9c7df61.
Report an issue: GitHub.