xai-org/grok-build · error

Server returned invalid user_code format (expected [A-Z0-9-]

Error message

Server returned invalid user_code format (expected [A-Z0-9-])

What it means

During OAuth2 device-authorization, the server's user_code is validated to contain only ASCII alphanumerics and hyphens before it is shown to the user. If the issuer returns a user_code with other characters (spaces, control chars, unicode), the client refuses to display it, defending against spoofing/injection from a malicious or buggy issuer.

Source

Thrown at crates/codegen/xai-grok-shell/src/auth/device_code.rs:177

    if !resp.status().is_success() {
        let status = resp.status();
        let body = resp.text().await.unwrap_or_default();
        if status.as_u16() == 404 {
            anyhow::bail!(DeviceCodeError::NotEnabled);
        }
        anyhow::bail!("Device code request failed (HTTP {status}): {body}");
    }

    let server_resp: DeviceCodeResponse = resp.json().await?;

    // Defend against control characters from a malicious issuer.
    if !server_resp
        .user_code
        .chars()
        .all(|c| c.is_ascii_alphanumeric() || c == '-')
    {
        anyhow::bail!("Server returned invalid user_code format (expected [A-Z0-9-])");
    }

    validate_verification_uri(&server_resp.verification_uri)?;
    if let Some(ref verification_uri_complete) = server_resp.verification_uri_complete {
        validate_verification_uri(verification_uri_complete)?;
    }

    Ok(DeviceCode {
        verification_uri: server_resp.verification_uri,
        verification_uri_complete: server_resp.verification_uri_complete,
        user_code: server_resp.user_code,
        device_code: server_resp.device_code,
        interval: server_resp
            .interval
            .unwrap_or(DEFAULT_DEVICE_POLL_INTERVAL_SECS),
        expires_in: server_resp.expires_in,
    })
}

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Check which authorization server you are hitting (XAI_API_BASE / base URL config) and ensure it is the genuine xAI OAuth2 issuer.
  2. Inspect the raw device-authorization response (curl -X POST <auth endpoint>/device/code) to see the actual user_code format.
  3. Update the xai-grok client to a version matching the server's current user_code format.
  4. If running your own proxy, make it pass through the issuer's user_code unchanged and conform to the expected alphabet.

Example fix

// server/proxy returning spaced user_code
{"user_code": "WDJB MJJT"}
// after: normalize to the expected alphabet
{"user_code": "WDJB-MJJT"}
Defensive patterns

Strategy: validation

Validate before calling

fn user_code_ok(code: &str) -> bool {
    !code.is_empty()
        && code.chars().all(|c| c.is_ascii_alphanumeric() || c == '-')
}
// call before displaying: if !user_code_ok(&resp.user_code) { abort }

Type guard

fn is_safe_user_code(s: &str) -> Option<&str> {
    let ok = s.chars().all(|c| c.is_ascii_alphanumeric() || c == '-');
    if ok { Some(s) } else { None }
}

Try / catch

match request_device_code(&client, &cfg).await {
    Ok(resp) => display(resp),
    Err(e) if e.to_string().contains("invalid user_code") => {
        eprintln!("Issuer returned unusable user_code; verify the auth server URL.");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: request_device_code receives a device-authorization response whose user_code field contains any character outside [A-Za-z0-9-] (e.g. 'ABCD EFGH', 'ab12_cd', or strings with control characters).

Common situations: Pointing the client at a non-xAI/proxied authorization server with a different user_code alphabet; a server-side regression changing the code format; a misconfigured base URL hitting an unintended endpoint that returns HTML or a different payload shape.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/e0019cdbc81c2f7d. Report an issue: GitHub.