{"record":{"id":"215db03cb7d64aa8","repo":"Hmbown/CodeWhale","slug":"no-patch-file-provided-and-stdin-is-empty","errorCode":null,"errorMessage":"No patch file provided and stdin is empty.","messagePattern":"No patch file provided and stdin is empty\\.","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/lib.rs","lineNumber":8445,"sourceCode":"        .ok_or_else(|| anyhow::anyhow!(\"git not found on PATH\"))?\n        .arg(\"apply\")\n        .arg(\"--whitespace=nowarn\")\n        .arg(&tmp_path)\n        .output()\n        .map_err(|e| anyhow::anyhow!(\"Failed to run git apply: {e}\"))?;\n\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        bail!(\"git apply failed: {}\", stderr.trim());\n    }\n    println!(\"Applied patch successfully.\");\n    Ok(())\n}\n\nfn read_patch_from_stdin() -> Result<String> {\n    let mut stdin = io::stdin();\n    if stdin.is_terminal() {\n        bail!(\"No patch file provided and stdin is empty.\");\n    }\n    let mut buffer = String::new();\n    stdin.read_to_string(&mut buffer)?;\n    Ok(buffer)\n}\n\nasync fn run_mcp_command(\n    config: &Config,\n    workspace: &Path,\n    command: McpCommand,\n    plugins: &crate::plugins::PluginRegistry,\n) -> Result<()> {\n    let config_path = config.mcp_config_path();\n    match command {\n        McpCommand::Init { force } => {\n            let status = init_mcp_config(&config_path, force)?;\n            match status {\n                WriteStatus::Created => {","sourceCodeStart":8427,"sourceCodeEnd":8463,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/lib.rs#L8427-L8463","documentation":"When no --patch-file is given, read_patch_from_stdin reads the patch from stdin -- but it bails immediately if stdin is a terminal (is_terminal()). Despite the wording, the check is 'stdin is a TTY', not 'stdin has no bytes': the guard stops the command from hanging while a human types. In non-TTY contexts an empty pipe is instead caught by the 'Patch is empty.' check.","triggerScenarios":"Running `codewhale apply` bare in an interactive shell; a wrapper that allocates a pseudo-TTY (expect, some CI steps) but supplies no patch.","commonSituations":"Forgetting the pipe or flag; docs example only half copy-pasted; running under a pty wrapper that makes stdin look interactive.","solutions":["Pipe the patch: `codewhale apply < patch.diff` or `producer | codewhale apply`","Or pass `--patch-file patch.diff`","In scripts, always redirect stdin explicitly (`</dev/null` when unused)"],"exampleFix":"# before\ncodewhale apply            # No patch file provided and stdin is empty.\n\n# after\ncodewhale apply < fix.diff","handlingStrategy":"validation","validationCode":"if [ -z \"$PATCH_FILE\" ] && [ -t 0 ]; then echo 'pass --patch-file or pipe a patch on stdin'; exit 1; fi\ncodewhale apply ${PATCH_FILE:+--patch-file \"$PATCH_FILE\"}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["In scripts, always redirect stdin explicitly (`< patch.diff` or `</dev/null`)","Wrap interactive usage in a check for a TTY before invoking apply with no args"],"tags":["stdin","cli-usage","patch","input-validation"],"backgroundTag":"missing-required-input","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}