{"record":{"id":"684f796516a7f503","repo":"Hmbown/CodeWhale","slug":"api-key-must-be-min-api-key-bytes-max-api-key-b","errorCode":null,"errorMessage":"API key must be {MIN_API_KEY_BYTES}-{MAX_API_KEY_BYTES} UTF-8 bytes","messagePattern":"API key must be (.+?)-(.+?) UTF-8 bytes","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/cli/src/cloud.rs","lineNumber":881,"sourceCode":"    }\n    Ok(())\n}\n\nfn validate_device_code(code: &str) -> Result<()> {\n    if code.len() != 43\n        || !code\n            .bytes()\n            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_'))\n    {\n        bail!(\"The Codewhale service returned an invalid device authorization response\");\n    }\n    Ok(())\n}\n\nfn validate_api_key(key: &str) -> Result<()> {\n    let bytes = key.len();\n    if bytes < MIN_API_KEY_BYTES || bytes as u64 > MAX_API_KEY_BYTES {\n        bail!(\"API key must be {MIN_API_KEY_BYTES}-{MAX_API_KEY_BYTES} UTF-8 bytes\");\n    }\n    if key.chars().any(is_ascii_control) {\n        bail!(\"API key contains invalid control characters\");\n    }\n    Ok(())\n}\n\nfn validate_label(label: &str) -> Result<String> {\n    let label = label.split_whitespace().collect::<Vec<_>>().join(\" \");\n    if label.is_empty()\n        || label.chars().count() > MAX_KEY_LABEL_CHARS\n        || label.chars().any(is_ascii_control)\n    {\n        bail!(\"key label must contain 1-{MAX_KEY_LABEL_CHARS} characters\");\n    }\n    Ok(label)\n}\n","sourceCodeStart":863,"sourceCodeEnd":899,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/cli/src/cloud.rs#L863-L899","documentation":"API keys accepted by the CLI (from config, secret store, env var, stdin, or hidden prompt) must be between 8 and 4096 UTF-8 bytes after trimming. This bail fires when the supplied key is shorter than 8 bytes or longer than 4096, catching empty, placeholder, and wrongly-pasted values before they reach the network.","triggerScenarios":"Passing an empty string, a 4-char placeholder like 'test', an email address, a whole JSON credential file, or a >4KiB token via --api-key-stdin, hidden prompt, config api_key, or provider env var.","commonSituations":"Piping the wrong file into --api-key-stdin (a JSON key file instead of the raw key); env vars containing quotes or 'Bearer ' prefixes making the value unexpected; copy-paste that misses characters; Windows CRLF adding bytes (handled by trim) or multi-line PEM blocks exceeding 4096 bytes.","solutions":["Re-copy the key and verify it is the raw token (typically 20-60 chars), not a JSON blob, URL, or 'Bearer'-prefixed string","If the key legitimately exceeds 4096 bytes, obtain a standard-length key from the provider","Check the env var (e.g. DEEPSEEK_API_KEY) for stray quotes, prefixes, or interpolation issues","For stdin, echo exactly the key: printf '%s' \"$KEY\" | codewhale ... --api-key-stdin"],"exampleFix":"# before\ncat account-credentials.json | codewhale cloud login --api-key-stdin\n# after\nprintf '%s' \"sk-actual-key-value\" | codewhale cloud login --api-key-stdin","handlingStrategy":"validation","validationCode":"const MIN_API_KEY_BYTES: usize = 8;\nconst MAX_API_KEY_BYTES: u64 = 4096;\n\nfn api_key_len_ok(key: &str) -> bool {\n    let bytes = key.trim().len();\n    (MIN_API_KEY_BYTES..=MAX_API_KEY_BYTES as usize).contains(&bytes)\n}","typeGuard":"fn is_valid_api_key(key: &str) -> bool {\n    let k = key.trim();\n    (8..=4096).contains(&k.len())\n        && !k.chars().any(|c| c <= '\\u{001f}' || c == '\\u{007f}')\n}","tryCatchPattern":null,"preventionTips":["Validate key length and charset before writing it to config or env","Extract the raw token field (jq -r .api_key) instead of piping whole files","Fail scripts early on empty/short key variables (set -u, : \"${KEY:?}\""],"tags":["cloud","api-key","validation","credentials"],"backgroundTag":"api-key-validation-failed","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}