{"record":{"id":"f5decced2419dec9","repo":"jdx/mise","slug":"details","errorCode":null,"errorMessage":"{details}","messagePattern":"\\{details\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/github/oauth.rs","lineNumber":371,"sourceCode":"                debug!(\"transient error polling GitHub OAuth token: {err:#}\");\n                continue;\n            }\n        };\n\n        match response.error.as_deref() {\n            None => return Ok(response),\n            Some(\"authorization_pending\") => continue,\n            Some(\"slow_down\") => {\n                interval += 5;\n                continue;\n            }\n            Some(\"expired_token\") => bail!(\"GitHub device authorization expired\"),\n            Some(\"access_denied\") => bail!(\"GitHub device authorization was denied\"),\n            Some(error) => {\n                let details = response\n                    .error_description\n                    .unwrap_or_else(|| error.to_string());\n                bail!(\"{details}\");\n            }\n        }\n    }\n}\n\nasync fn refresh_token(cached: &CachedToken) -> Result<Option<CachedToken>> {\n    let Some(refresh_token) = cached.refresh_token.as_deref() else {\n        return Ok(None);\n    };\n    if cached\n        .refresh_expires_at\n        .is_some_and(|exp| exp <= chrono::Utc::now())\n    {\n        return Ok(None);\n    }\n\n    let settings = Settings::get();\n    let url = format!(","sourceCodeStart":353,"sourceCodeEnd":389,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/github/oauth.rs#L353-L389","documentation":"Catch-all branch of poll_access_token: GitHub returned an unrecognized device-flow error code, so mise bails with the server-provided error_description if present, otherwise the raw error code string. The message content is entirely determined by GitHub's response, e.g. 'grant requires SSO authorization' or a client_id problem.","triggerScenarios":"poll_access_token matches Some(error) where error is none of authorization_pending/slow_down/expired_token/access_denied — e.g. \"unsupported_grant_type\", \"incorrect_client_id\", SSO-required errors — and bails with the response's error_description (or the code itself if absent).","commonSituations":"Misconfigured settings.github.oauth_client_id (empty, wrong app); organization requires SAML SSO authorization for the OAuth app; GitHub API contract changes introducing a new error code.","solutions":["Read the actual message (the GitHub error_description) — it names the root cause (e.g. incorrect_client_id).","Check settings.github.oauth_client_id: it must be a valid GitHub OAuth app client id; fix or clear the setting.","If the org requires SSO, authorize the OAuth app for SAML SSO in the org's developer settings.","Retry the flow with `mise token github --oauth`; if GitHub reports a transient error it may succeed on retry."],"exampleFix":"// before (config.toml)\n[github]\noauth_client_id = \"\"\n// error: incorrect_client_id\n\n// after\n[github]\noauth_client_id = \"Ov23liXXXXXXXXXXXXXX\"","handlingStrategy":"try-catch","validationCode":"let cid = &config.settings.github.oauth_client_id;\nif cid.trim().is_empty() {\n    eprintln!(\"settings.github.oauth_client_id is unset/invalid; fix before OAuth\");\n}","typeGuard":"fn has_valid_client_id(s: &Settings) -> bool {\n    !s.github.oauth_client_id.trim().is_empty()\n}","tryCatchPattern":"match token_async(req).await {\n    Err(e) => {\n        // message is GitHub's error_description; surface it to the user verbatim\n        eprintln!(\"GitHub device flow failed: {e}\");\n    }\n    Ok(t) => use_token(&t),\n}","preventionTips":["Validate settings.github.oauth_client_id contains a real OAuth app client id before starting the flow.","Authorize the OAuth app for SAML SSO in organizations that require it.","Keep mise updated so new GitHub error codes are handled explicitly.","Log the full error_description when debugging device-flow failures."],"tags":["github","oauth","device-flow","api-error"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}