{"record":{"id":"a4a5ed2ec3abc0e2","repo":"Hmbown/CodeWhale","slug":"no-api-key-provided-via-stdin","errorCode":null,"errorMessage":"No API key provided via stdin.","messagePattern":"No API key provided via stdin\\.","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/lib.rs","lineNumber":7773,"sourceCode":"/// silently falling back to a route classifier or an older config.toml value.\nfn apply_saved_reasoning_preference(config: &mut Config, settings: &crate::settings::Settings) {\n    let Some(reasoning_effort) = settings.reasoning_effort.as_ref() else {\n        return;\n    };\n    config.reasoning_effort = Some(reasoning_effort.clone());\n    config.reasoning_effort_inferred_from_legacy_alias = false;\n}\n\nfn read_api_key_from_stdin() -> Result<String> {\n    let mut stdin = io::stdin();\n    if stdin.is_terminal() {\n        bail!(\"No API key provided. Pass --api-key or pipe one via stdin.\");\n    }\n    let mut buffer = String::new();\n    stdin.read_to_string(&mut buffer)?;\n    let api_key = buffer.trim().to_string();\n    if api_key.is_empty() {\n        bail!(\"No API key provided via stdin.\");\n    }\n    Ok(api_key)\n}\n\nfn run_login(api_key: Option<String>) -> Result<()> {\n    let api_key = match api_key {\n        Some(key) => key,\n        None => read_api_key_from_stdin()?,\n    };\n    let saved = config::save_api_key(&api_key)?;\n    println!(\"Saved API key to {}\", saved.describe());\n    Ok(())\n}\n\nfn run_logout() -> Result<()> {\n    config::clear_api_key()?;\n    println!(\"Cleared saved API key.\");\n    Ok(())","sourceCodeStart":7755,"sourceCodeEnd":7791,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/lib.rs#L7755-L7791","documentation":"The stdin branch of read_api_key_from_stdin(): stdin was piped (not a TTY) but its content trimmed to an empty string. The CLI distinguishes this from the no-pipe case (error 469) so scripts can tell an empty pipe from a missing one. Even a newline-only pipe trims to empty and fails.","triggerScenarios":"`codewhale login` with no --api-key and stdin piped but blank: an unset/empty variable (`echo \"$VAR\" |`), an empty file redirect, or a producer that emitted only whitespace.","commonSituations":"CI job where the secret's variable name is misspelled or the secret was never injected; piping from a failed command's empty output; redirecting an empty key file.","solutions":["Guard the source: `: \"${VAR:?msg}\"` fails fast on unset/empty variables","Verify a piped file is non-empty: `[ -s key.txt ]`","Or bypass stdin entirely with `codewhale login --api-key <key>`"],"exampleFix":"// before: VAR unset -> pipe delivers only a newline\n$ echo \"$MY_KEY\" | codewhale login\nError: No API key provided via stdin.\n\n// after\n$ : \"${MY_KEY:?MY_KEY is empty}\" && printf '%s' \"$MY_KEY\" | codewhale login","handlingStrategy":"validation","validationCode":"[ -n \"${CODEWHALE_API_KEY:-}\" ] || { echo 'key variable empty' >&2; exit 2; }\nprintf '%s' \"$CODEWHALE_API_KEY\" | codewhale login","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use : \"${VAR:?msg}\" and `[ -s file ]` checks before piping","Log pipe provenance in CI so an empty secret is obvious"],"tags":["auth","api-key","login","stdin","empty-input"],"backgroundTag":"missing-api-key","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}