Hmbown/CodeWhale · error

offers no browser sign-in flow

Error message

{} offers no browser sign-in flow

What it means

During the PKCE browser sign-in flow, the provider's parameter set has no `authorize_path`, meaning no authorization endpoint is defined for it. The library refuses to construct an authorize URL because the provider (e.g. xAI) simply does not support browser-based OAuth sign-in. This is a guard so the flow fails with a clear reason instead of building a malformed or missing URL.

Solutions

  1. Use the device-code login flow for this provider instead (e.g. `codewhale auth xai-device`).
  2. Check `oauth_provider_params(provider)` for the chosen provider and pick one that defines `authorize_path`.
  3. If you own a custom provider config, add the correct `authorize_path` for its issuer.

Example fix

// before
codewhale auth login --provider xai   // browser flow, xAI has no authorize_path
// after
codewhale auth xai-device             // device-code flow
Defensive patterns

Strategy: validation

Validate before calling

let params = oauth_provider_params(provider);
if params.authorize_path.is_none() {
    // fall back to device-code flow instead of browser PKCE
    return device_code_login(provider).await;
}

Type guard

fn supports_browser_flow(params: &OAuthProviderParams) -> bool {
    params.authorize_path.is_some()
}

Prevention

When it happens

Trigger: Calling the internal authorize-URL builder (the function taking `scopes`, `redirect_uri`, `state`, `pkce`) with an `OAuthProviderParams` whose `authorize_path` is `None` — i.e. a provider configured without a browser authorization endpoint, such as xAI.

Common situations: Running `codewhale` browser login against a provider that only supports device-code login; a provider config/registry entry missing `authorize_path`; wiring a custom provider params struct without setting `authorize_path`.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/277f126f4ae5b354. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/oauth.rs:1147

        let chunk = uuid::Uuid::new_v4();
        let take = (bytes.len() - offset).min(16);
        bytes[offset..offset + take].copy_from_slice(&chunk.as_bytes()[..take]);
        offset += take;
    }
    URL_SAFE_NO_PAD.encode(bytes)
}

pub fn build_authorize_url(
    params: &OAuthProviderParams,
    issuer: &str,
    client_id: &str,
    scopes: &str,
    redirect_uri: &str,
    state: &str,
    pkce: &PkceChallenge,
) -> Result<String> {
    let Some(authorize_path) = params.authorize_path else {
        bail!("{} offers no browser sign-in flow", params.display_name);
    };
    // A malformed configured issuer must fail loudly. Silently redirecting
    // the browser to the production authorize endpoint would hand the
    // issuer a sign-in the user aimed somewhere else.
    let issuer_var = params
        .env
        .issuer_vars
        .first()
        .copied()
        .unwrap_or("the issuer environment variable");
    let mut url = oauth_endpoint_url(&format!(
        "{}/{}",
        issuer.trim_end_matches('/'),
        authorize_path
    ))
    .with_context(|| {
        format!(
            "{} OAuth issuer is not a valid URL or uses an insecure endpoint — check {issuer_var}",

View on GitHub (pinned to 73e0f67d83)