{"record":{"id":"e38cc9ff84ca4b74","repo":"Hmbown/CodeWhale","slug":"no-api-key-provided-pass-api-key-or-pipe-one-vi","errorCode":null,"errorMessage":"No API key provided. Pass --api-key or pipe one via stdin.","messagePattern":"No API key provided\\. Pass --api-key or pipe one via stdin\\.","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/lib.rs","lineNumber":7767,"sourceCode":"/// Apply the same reasoning-preference precedence as interactive `App`\n/// construction to non-TUI runtimes.\n///\n/// `/model` and the config editor persist this preference in `settings.toml`.\n/// Exec, review, workflow, ACP, and runtime-thread launches all begin with a\n/// `Config`, so copying the saved value here keeps those entry points from\n/// 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(())","sourceCodeStart":7749,"sourceCodeEnd":7785,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/lib.rs#L7749-L7785","documentation":"run_login() with no --api-key falls back to read_api_key_from_stdin(), which first checks io::stdin().is_terminal(). If stdin is an interactive terminal it bails immediately with this message rather than hanging on hidden input; piping is the designed non-interactive path.","triggerScenarios":"Running `codewhale login` without --api-key from an interactive shell (stdin is a TTY). Any piped invocation takes the stdin branch instead and never sees this message.","commonSituations":"Typing `codewhale login` expecting a password-style hidden prompt (there is none); forgetting the flag during a quick local test.","solutions":["Pass the key explicitly: `codewhale login --api-key <key>`","Or pipe it: `printf '%s' \"$CODEWHALE_API_KEY\" | codewhale login`","In scripts, always source the key from a variable or secret store rather than expecting a prompt"],"exampleFix":"// before (interactive tty, no key)\n$ codewhale login\nError: No API key provided. Pass --api-key or pipe one via stdin.\n\n// after\n$ codewhale login --api-key \"$CODEWHALE_API_KEY\"\n// or: $ printf '%s' \"$CODEWHALE_API_KEY\" | codewhale login","handlingStrategy":"validation","validationCode":": \"${CODEWHALE_API_KEY:?set CODEWHALE_API_KEY or pass --api-key}\"\ncodewhale login --api-key \"$CODEWHALE_API_KEY\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fail fast on missing key variables with : \"${VAR:?}\"","Store the key in the environment or a secret manager, not in shell history"],"tags":["auth","api-key","login","stdin"],"backgroundTag":"missing-api-key","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}