Hmbown/CodeWhale · warning
offers no device-code flow; sign in through the browser…
Error message
{} offers no device-code flow; sign in through the browser login instead What it means
Fail-fast guard in `device_code_login` thrown before any network or thread spawn when the provider's static parameters have no `device_code_path`. The provider simply does not implement the RFC 8628 device flow, so device-code sign-in is not possible; the message directs the user to the browser (PKCE) login.
Solutions
- Use the browser/PKCE sign-in flow for this provider instead (`{provider} login` without the device option)
- Check `oauth_provider_params` to confirm which flows the provider supports
- If device flow is expected, verify you are targeting a provider build/config that defines `device_code_path`
Example fix
// before
let pending = device_code_login(provider)?; // bails for PKCE-only providers
// after
if supports_device_flow(provider) {
let pending = device_code_login(provider)?;
} else {
let pending = pkce_login(provider).await?;
} Defensive patterns
Strategy: validation
Validate before calling
// check flow support before calling device login
const params = oauthProviderParams(provider);
if (!params.device_code_path) {
return pkceLogin(provider); // or surface a clear message
} Type guard
function supportsDeviceFlow(provider) {
return oauthProviderParams(provider)?.device_code_path != null;
} Try / catch
try {
await deviceCodeLogin(provider);
} catch (e) {
if (String(e).includes('no device-code flow')) {
await pkceLogin(provider); // fallback to browser login
} else { throw e; }
} Prevention
- Consult the provider capability table before choosing a login flow
- Offer users the browser (PKCE) login as the default when device flow is unavailable
- Keep provider flow support documented next to the provider list
When it happens
Trigger: Calling `device_code_login(provider)` for a provider whose `oauth_provider_params` entry has `device_code_path: None` (e.g. a provider that only supports the authorization-code/PKCE flow).
Common situations: Selecting the device-code sign-in option for a PKCE-only provider; config or code update removing the device flow for a provider; scripting a login flow that assumes all providers support device grants.
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
- returned an unusable verification URI
- {}
- offers no device-code flow; sign in through the browser…
- {message}
- offers no browser sign-in flow; sign in through the…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/05a6cc72a65196a7.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/oauth.rs:810
body.error_description.as_deref(),
status,
);
bail!("OAuth device-code poll failed ({detail})");
}
}
}
/// Interactive device-code login for any provider whose row offers it.
/// Prints the verification URL + user code to stderr and polls until
/// approved. A provider with no device flow (ChatGPT) fails here with the
/// reason, instead of deep in transport code.
pub async fn device_code_login(provider: OAuthProvider) -> Result<PendingOAuthLogin> {
// Endpoint resolution does blocking HTTP (discovery): it must run on the
// blocking worker, never on the async executor. Providers with no device
// flow fail here, before any thread spawns and before any network.
let params = oauth_provider_params(provider);
if params.device_code_path.is_none() {
bail!(
"{} offers no device-code flow; sign in through the browser login instead",
params.display_name
);
}
let inputs = params.resolve_inputs();
let display_name = params.display_name;
tokio::task::spawn_blocking(move || device_code_login_with(provider, &inputs))
.await
.with_context(|| format!("{display_name} device-code login worker failed"))?
}
/// Blocking worker body for [`device_code_login`]. `pub(crate)` so the
/// legacy activation tests can drive the unified login end to end until
/// activation unifies in 3b-ii.
pub(crate) fn device_code_login_with(
provider: OAuthProvider,
inputs: &ResolvedOAuthInputs,
) -> Result<PendingOAuthLogin> {View on GitHub (pinned to 73e0f67d83)