Hmbown/CodeWhale · error · anyhow::Error
API key contains invalid control characters
Error message
API key contains invalid control characters
What it means
After the length check, the CLI rejects any API key containing ASCII control characters (code points <= 0x1f or 0x7f DEL). This bail fires when the key value embeds newlines, carriage returns, tabs, NULs, or escape bytes - usually the residue of how the value was stored or transported rather than the key itself.
Source
Thrown at crates/cli/src/cloud.rs:884
fn validate_device_code(code: &str) -> Result<()> {
if code.len() != 43
|| !code
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_'))
{
bail!("The Codewhale service returned an invalid device authorization response");
}
Ok(())
}
fn validate_api_key(key: &str) -> Result<()> {
let bytes = key.len();
if bytes < MIN_API_KEY_BYTES || bytes as u64 > MAX_API_KEY_BYTES {
bail!("API key must be {MIN_API_KEY_BYTES}-{MAX_API_KEY_BYTES} UTF-8 bytes");
}
if key.chars().any(is_ascii_control) {
bail!("API key contains invalid control characters");
}
Ok(())
}
fn validate_label(label: &str) -> Result<String> {
let label = label.split_whitespace().collect::<Vec<_>>().join(" ");
if label.is_empty()
|| label.chars().count() > MAX_KEY_LABEL_CHARS
|| label.chars().any(is_ascii_control)
{
bail!("key label must contain 1-{MAX_KEY_LABEL_CHARS} characters");
}
Ok(label)
}
fn is_ascii_control(character: char) -> bool {
character <= '\u{001f}' || character == '\u{007f}'
}View on GitHub (pinned to 0c42157ee5)
Solutions
- Strip interior control bytes before storing: tr -d '\r\n\000' < key.txt
- Fix the env var or config entry to contain the single-line key with no escapes
- Re-paste the key manually in the hidden prompt to eliminate paste artifacts
- If a secrets manager wraps keys, extract the raw token field instead of the wrapper
Example fix
# before printf 'sk-abc\nsk-def' | codewhale cloud login --api-key-stdin # interior newline # after printf '%s' "$(tr -d '\r\n' < key.txt)" | codewhale cloud login --api-key-stdin
Defensive patterns
Strategy: validation
Validate before calling
fn has_no_control_chars(s: &str) -> bool {
!s.chars().any(|c| c <= '\u{001f}' || c == '\u{007f}')
} Type guard
fn is_sanitized_api_key(key: &str) -> bool {
(8..=4096).contains(&key.trim().len())
&& !key.trim().chars().any(|c| c <= '\u{001f}' || c == '\u{007f}')
} Prevention
- tr -d '\r\n\000' any key material piped from files on any OS
- Avoid multi-line secrets wrappers; store the bare token
- Assert single-line keys in provisioning scripts before use
When it happens
Trigger: A key passed via --api-key-stdin or a prompt containing an embedded \n or \r; an env var set with a literal escape sequence; a config file value with a stray tab; binary garbage pasted into the prompt.
Common situations: Windows CRLF line endings when piping key files; secrets managers that store multi-line values; shell quoting that preserves \n escape sequences instead of newlines being trimmed (leading/trailing are trimmed, interior ones are not); terminal paste glitches.
Related errors
- API key must be {MIN_API_KEY_BYTES}-{MAX_API_KEY_BYTES} UTF-
- key label must contain 1-{MAX_KEY_LABEL_CHARS} characters
- The Codewhale service returned an account without an ID
- The Codewhale service returned an invalid user code
- The Codewhale service returned an invalid device authorizati
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/b09ef7775a9cc793.
Report an issue: GitHub.