Hmbown/CodeWhale · error · anyhow::Error

The Codewhale service returned an invalid user code

Error message

The Codewhale service returned an invalid user code

What it means

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.

Source

Thrown at crates/cli/src/cloud.rs:862

        .unwrap_or(host);
    host.eq_ignore_ascii_case("localhost")
        || host
            .parse::<IpAddr>()
            .is_ok_and(|address| address.is_loopback())
}

fn validate_user_code(code: &str) -> Result<()> {
    const ALPHABET: &[u8] = b"ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
    let bytes = code.as_bytes();
    if bytes.len() != 14
        || bytes[4] != b'-'
        || bytes[9] != b'-'
        || bytes
            .iter()
            .enumerate()
            .any(|(index, byte)| !matches!(index, 4 | 9) && !ALPHABET.contains(byte))
    {
        bail!("The Codewhale service returned an invalid user code");
    }
    Ok(())
}

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 {

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Regenerate codes in the format XXXXX-XXXXX-XXXX using only A-Z without I/O and digits 2-9
  2. Strip surrounding whitespace before validating if the value comes from a file or env var
  3. Update the CLI to the release matching the service's user-code format
  4. If writing a test backend, reuse the exact alphabet constant to avoid off-by-one look-alike characters

Example fix

// before
user_code: "ABCD0EFGH1JKLM"
// after
user_code: "ABCDE-FGHIJ-KLMN"  // 14 chars, dashes at 4 and 9, no 0/1/I/O
Defensive patterns

Strategy: validation

Validate before calling

const USER_CODE_ALPHABET: &[u8] = b"ABCDEFGHJKLMNPQRSTUVWXYZ23456789";

fn is_valid_user_code(code: &str) -> bool {
    let b = code.as_bytes();
    b.len() == 14
        && b[4] == b'-'
        && b[9] == b'-'
        && b.iter().enumerate().all(|(i, &c)|
            matches!(i, 4 | 9) || USER_CODE_ALPHABET.contains(&c))
}

Type guard

fn is_valid_user_code(code: &str) -> bool {
    let b = code.as_bytes();
    b.len() == 14 && b[4] == b'-' && b[9] == b'-'
        && b.iter().enumerate()
            .all(|(i, &c)| matches!(i, 4 | 9) || b"ABCDEFGHJKLMNPQRSTUVWXYZ23456789".contains(&c))
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/955f2f9afdd44049. Report an issue: GitHub.