{"record":{"id":"8b3789952856f842","repo":"zeroclaw-labs/zeroclaw","slug":"no-input-received-from-stdin","errorCode":null,"errorMessage":"No input received from stdin","messagePattern":"No input received from stdin","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/cli_input.rs","lineNumber":136,"sourceCode":"    pub fn interact_text(self) -> Result<String> {\n        let stdin = std::io::stdin();\n        let stdout = std::io::stdout();\n        self.interact_text_with_io(stdin.lock(), stdout.lock())\n    }\n\n    fn interact_text_with_io<R: BufRead, W: Write>(\n        self,\n        mut reader: R,\n        mut writer: W,\n    ) -> Result<String> {\n        loop {\n            write!(writer, \"{}\", self.render_prompt())?;\n            writer.flush()?;\n\n            let mut line = String::new();\n            let bytes_read = reader.read_line(&mut line)?;\n            if bytes_read == 0 {\n                bail!(\"No input received from stdin\");\n            }\n\n            let trimmed = trim_trailing_line_ending(&line);\n            if trimmed.is_empty() {\n                if let Some(default) = &self.default {\n                    return Ok(default.clone());\n                }\n                if self.allow_empty {\n                    return Ok(String::new());\n                }\n                writeln!(writer, \"Input cannot be empty.\")?;\n                continue;\n            }\n\n            return Ok(trimmed.to_string());\n        }\n    }\n","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/cli_input.rs#L118-L154","documentation":"interact_text_with_io writes the prompt, flushes, then reads one line from stdin. read_line returning 0 bytes is EOF (stream closed — not the same as an empty line), and the helper bails immediately. Note the configured .default() value only applies to a blank line; EOF never falls back to the default.","triggerScenarios":"User presses Ctrl-D at the prompt; a script pipes zero bytes then closes stdin (e.g. `true | zeroclaw ...`); stdin was already exhausted by an earlier prompt in the same process.","commonSituations":"CLI invoked non-interactively in CI/cron/piped contexts without input; here-docs consumed by a previous read; test harnesses that close stdin; dropped ssh sessions.","solutions":["Attach a TTY or provide input on stdin when the command prompts","Handle this error at the call site and substitute your own fallback on EOF","When scripting and you want the configured default, pipe a newline (blank line) instead of closing stdin","For non-interactive flows, pass values via flags or config instead of interactive prompts"],"exampleFix":"// before\nlet value = prompt.interact_text()?; // Ctrl-D aborts the whole program\n\n// after\nlet value = match prompt.interact_text() {\n    Ok(v) => v,\n    Err(e) if e.to_string().contains(\"No input received from stdin\") => fallback.clone(),\n    Err(e) => return Err(e),\n};","handlingStrategy":"try-catch","validationCode":"use std::io::IsTerminal;\nif !std::io::stdin().is_terminal() {\n    // non-interactive context: take values from flags/config instead of prompting\n    return Ok(config_value);\n}","typeGuard":null,"tryCatchPattern":"let value = match prompt.interact_text() {\n    Ok(v) => v,\n    Err(ref e) if e.to_string().contains(\"No input received from stdin\") => fallback.clone(),\n    Err(e) => return Err(e),\n};","preventionTips":["Pipe a newline rather than closing stdin when you want the configured default on empty input","Provide flag/config equivalents for every interactive prompt so CI never blocks","In test harnesses, keep stdin open or mock the IO pair instead of closing it","Treat EOF as 'no answer', never as an error worth crashing on in interactive CLIs"],"tags":["stdin","eof","cli","interactive-prompt"],"backgroundTag":"stdin-eof","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}