Hmbown/CodeWhale · error
offers no sign-in flow
Error message
{} offers no sign-in flow What it means
Thrown by the top-level sign-in dispatcher when a provider has neither `device_code_path` nor `authorize_path`, meaning no sign-in flow exists at all for it. This is a configuration/code-table invariant guard rather than a network failure.
Solutions
- Check the provider name you passed against the supported provider list in `oauth_provider_params`
- Use the provider's non-OAuth auth method (e.g. API key) if it defines no OAuth flows
- Add `device_code_path` or `authorize_path` to the provider row if you maintain this provider definition
Defensive patterns
Strategy: validation
Validate before calling
// ensure the provider defines at least one sign-in flow
const params = oauthProviderParams(provider);
if (!params?.device_code_path && !params?.authorize_path) {
throw new Error(`${provider} has no OAuth sign-in flow configured`);
} Type guard
function hasSignInFlow(provider) {
const p = oauthProviderParams(provider);
return p != null && (p.device_code_path != null || p.authorize_path != null);
} Try / catch
try {
await signIn(provider);
} catch (e) {
if (String(e).includes('offers no sign-in flow')) {
console.error(`No OAuth flow for ${provider}; use API-key auth instead.`);
} else { throw e; }
} Prevention
- Validate provider names against the supported list before invoking sign-in
- Register every new provider with at least one auth path in `oauth_provider_params`
- Document API-key-only providers so callers do not request OAuth sign-in
When it happens
Trigger: Calling the sign-in entry point with a provider whose `oauth_provider_params` row defines neither a device-code path nor a PKCE authorize path (or an unknown/typo'd provider mapping).
Common situations: Passing an invalid or newly-added provider name not yet wired into `oauth_provider_params`; provider intentionally login-less (API-key only) being used where OAuth sign-in is requested.
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
- Codewhale-owned OAuth credentials are not configured
- Codewhale-owned xAI OAuth credentials are inactive until…
- invalid Codewhale-owned ChatGPT OAuth generation; expected…
- invalid Codewhale-owned xAI OAuth generation; expected…
- invalid MCP OAuth callback port 0
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/65cdcd5c4ccf88f2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/oauth.rs:910
Ok(PendingOAuthLogin {
provider,
issuer: inputs.issuer.clone(),
client_id: inputs.client_id.clone(),
token,
})
}
/// One login entry point for every provider: the params row decides whether
/// the grant is device-code or browser PKCE. A provider with neither fails
/// here with the reason.
pub async fn login(provider: OAuthProvider) -> Result<PendingOAuthLogin> {
let params = oauth_provider_params(provider);
if params.device_code_path.is_some() {
device_code_login(provider).await
} else if params.authorize_path.is_some() {
pkce_login(provider).await
} else {
bail!("{} offers no sign-in flow", params.display_name);
}
}
// ── form-post transport seam ──────────────────────────────────────────
//
// One seam for every OAuth form post (PKCE exchange, refresh, revoke): the
// production client is reqwest with the shared bounds; tests substitute a
// mock issuer. The seam records network/refresh in test builds so the
// side-effect trap can still prove "zero external I/O" assertions.
pub(crate) trait OAuthFormClient {
fn post_form(&self, url: &str, form: &[(&str, &str)]) -> Result<(u16, String)>;
}
pub(crate) struct ReqwestOAuthFormClient;
impl OAuthFormClient for ReqwestOAuthFormClient {
fn post_form(&self, url: &str, form: &[(&str, &str)]) -> Result<(u16, String)> {View on GitHub (pinned to 73e0f67d83)