{"record":{"id":"9589842a66aadcf0","repo":"zeroclaw-labs/zeroclaw","slug":"github-auth-failed-error","errorCode":null,"errorMessage":"GitHub auth failed: {error}","messagePattern":"GitHub auth failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/copilot.rs","lineNumber":602,"sourceCode":"                .send()\n                .await?\n                .json()\n                .await?;\n\n            if let Some(token) = token_response.access_token {\n                eprintln!(\"Authentication succeeded.\\n\");\n                return Ok(token);\n            }\n\n            match token_response.error.as_deref() {\n                Some(\"slow_down\") => {\n                    poll_interval += Duration::from_secs(5);\n                }\n                Some(\"authorization_pending\") | None => {}\n                Some(\"expired_token\") => {\n                    anyhow::bail!(\"GitHub device authorization expired\")\n                }\n                Some(error) => anyhow::bail!(\"GitHub auth failed: {error}\"),\n            }\n        }\n\n        anyhow::bail!(\"Timed out waiting for GitHub authorization\")\n    }\n\n    /// Exchange a GitHub access token for a Copilot API key.\n    async fn exchange_for_api_key(&self, access_token: &str) -> anyhow::Result<ApiKeyInfo> {\n        let mut request = self.http_client().get(GITHUB_API_KEY_URL);\n        for (header, value) in &Self::COPILOT_HEADERS {\n            request = request.header(*header, *value);\n        }\n        request = request.header(\"Authorization\", format!(\"token {access_token}\"));\n\n        let response = request.send().await?;\n\n        if !response.status().is_success() {\n            let status = response.status();","sourceCodeStart":584,"sourceCodeEnd":620,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/copilot.rs#L584-L620","documentation":"The GitHub device-flow token endpoint returned an error code other than the handled slow_down, authorization_pending, and expired_token cases. The raw GitHub error code is embedded in the message; common ones are access_denied (user denied the permission prompt), incorrect_device_code, and incorrect_client_id.","triggerScenarios":"User clicks cancel or deny on the GitHub authorization page; the device_code is replayed after expiry; GitHub rejects the OAuth client_id (suspended or blocked app); device flow disabled by policy for the account.","commonSituations":"User denies the requested scopes; a GitHub org policy restricts the OAuth app; retrying a flow with a stale device code; enterprise-managed accounts blocking third-party device flow.","solutions":["If the code is access_denied: the user must accept the permission prompt - restart the login","For any other code, restart the device flow to obtain a fresh device_code","If it persists, check whether your organization's OAuth app policy blocks the ZeroClaw GitHub app","Alternatively configure a personal access token directly instead of device flow"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match copilot_login().await {\n    Ok(token) => { /* store token */ }\n    Err(e) if e.to_string().contains(\"GitHub auth failed\") => {\n        // read the embedded code: access_denied needs user consent on retry;\n        // anything else usually needs a fresh device code or a PAT fallback\n        if e.to_string().contains(\"access_denied\") {\n            return Err(anyhow::anyhow!(\"user denied GitHub authorization; retry when ready\"));\n        }\n        // else: restart the flow once with a fresh device code\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Tell users to click Authorize, not Cancel, on the GitHub permission page","Never reuse a device code across login attempts","Check org OAuth app policies before deploying device-flow logins in enterprises","Keep a PAT-based config path as fallback where device flow is blocked"],"tags":["github","oauth","device-flow","copilot","rust"],"backgroundTag":"oauth-device-flow-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}