{"record":{"id":"955f2f9afdd44049","repo":"Hmbown/CodeWhale","slug":"the-codewhale-service-returned-an-invalid-user-cod","errorCode":null,"errorMessage":"The Codewhale service returned an invalid user code","messagePattern":"The Codewhale service returned an invalid user code","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/cli/src/cloud.rs","lineNumber":862,"sourceCode":"        .unwrap_or(host);\n    host.eq_ignore_ascii_case(\"localhost\")\n        || host\n            .parse::<IpAddr>()\n            .is_ok_and(|address| address.is_loopback())\n}\n\nfn validate_user_code(code: &str) -> Result<()> {\n    const ALPHABET: &[u8] = b\"ABCDEFGHJKLMNPQRSTUVWXYZ23456789\";\n    let bytes = code.as_bytes();\n    if bytes.len() != 14\n        || bytes[4] != b'-'\n        || bytes[9] != b'-'\n        || bytes\n            .iter()\n            .enumerate()\n            .any(|(index, byte)| !matches!(index, 4 | 9) && !ALPHABET.contains(byte))\n    {\n        bail!(\"The Codewhale service returned an invalid user code\");\n    }\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 {","sourceCodeStart":844,"sourceCodeEnd":880,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/cli/src/cloud.rs#L844-L880","documentation":"The CLI validates the user_code from a device-authorization response against a strict format: exactly 14 bytes, dashes at byte offsets 4 and 9, and all other characters in the 32-symbol alphabet ABCDEFGHJKLMNPQRSTUVWXYZ23456789 (no I, O, 0, or 1, to avoid look-alikes). This bail fires when the service-issued code deviates from that shape.","triggerScenarios":"validate_user_code receives a code like 'ABCD/EFGH/JKLM' (wrong separator), 13 or 15 characters, lowercase letters, or characters 0/1/I/O anywhere; also whitespace or a newline accidentally included in the parsed value.","commonSituations":"A mock or alternative backend generating codes with a different alphabet or grouping; truncation or padding when the code is stored/echoed; a service version that switched to a denser or shorter code format than the CLI accepts.","solutions":["Regenerate codes in the format XXXXX-XXXXX-XXXX using only A-Z without I/O and digits 2-9","Strip surrounding whitespace before validating if the value comes from a file or env var","Update the CLI to the release matching the service's user-code format","If writing a test backend, reuse the exact alphabet constant to avoid off-by-one look-alike characters"],"exampleFix":"// before\nuser_code: \"ABCD0EFGH1JKLM\"\n// after\nuser_code: \"ABCDE-FGHIJ-KLMN\"  // 14 chars, dashes at 4 and 9, no 0/1/I/O","handlingStrategy":"validation","validationCode":"const USER_CODE_ALPHABET: &[u8] = b\"ABCDEFGHJKLMNPQRSTUVWXYZ23456789\";\n\nfn is_valid_user_code(code: &str) -> bool {\n    let b = code.as_bytes();\n    b.len() == 14\n        && b[4] == b'-'\n        && b[9] == b'-'\n        && b.iter().enumerate().all(|(i, &c)|\n            matches!(i, 4 | 9) || USER_CODE_ALPHABET.contains(&c))\n}","typeGuard":"fn is_valid_user_code(code: &str) -> bool {\n    let b = code.as_bytes();\n    b.len() == 14 && b[4] == b'-' && b[9] == b'-'\n        && b.iter().enumerate()\n            .all(|(i, &c)| matches!(i, 4 | 9) || b\"ABCDEFGHJKLMNPQRSTUVWXYZ23456789\".contains(&c))\n}","tryCatchPattern":null,"preventionTips":["Generate codes as XXXXX-XXXXX-XXXXX from the 32-symbol no-look-alike alphabet","Round-trip test generator output through the validator in CI","Trim whitespace from codes captured in files/env before validating"],"tags":["cloud","oauth","device-flow","validation"],"backgroundTag":"oauth-user-code-format","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}