{"record":{"id":"e5f3601d42bf8b37","repo":"zeroclaw-labs/zeroclaw","slug":"timed-out-waiting-for-github-authorization","errorCode":null,"errorMessage":"Timed out waiting for GitHub authorization","messagePattern":"Timed out waiting for GitHub authorization","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/copilot.rs","lineNumber":606,"sourceCode":"\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();\n            let body = response.text().await.unwrap_or_default();\n            let sanitized = super::sanitize_api_error(&body);\n\n            if status.as_u16() == 401 || status.as_u16() == 403 {","sourceCodeStart":588,"sourceCodeEnd":624,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/copilot.rs#L588-L624","documentation":"The device-flow poll loop ran until its expires_in deadline without the token endpoint returning success or a terminal error - the while condition Instant::now() < expires_at went false while polling was still effectively pending. This is the timeout backstop at the end of device_code_login, not a GitHub-reported error.","triggerScenarios":"Polling authorization_pending for the full code lifetime without confirmation: user never completed authorization, poll intervals stretched by network latency, or a system clock jump made expires_at appear to pass early.","commonSituations":"User took longer than the code lifetime; NTP stepped the clock mid-flow; congested network stretching each poll cycle; user authorized just after the window closed.","solutions":["Re-run the login and authorize promptly when the code appears","Ensure the system clock is correct (NTP) so the expiry window is computed accurately","Check network stability to github.com - repeated slow polls can consume the window","If it recurs, verify how long the terminal says the code is valid and complete the browser step immediately"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match copilot_login().await {\n    Ok(token) => { /* store token */ }\n    Err(e) if e.to_string().contains(\"Timed out waiting for GitHub authorization\") => {\n        copilot_login().await // one restart: the previous code is dead anyway\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Complete the browser authorization immediately after the code appears","Keep system clocks NTP-synced so the expiry window is not miscomputed","Avoid running device login over flaky links; each slow poll eats the window","Prompt the user again if login has been pending for several minutes"],"tags":["github","oauth","device-flow","timeout","rust"],"backgroundTag":"device-flow-authorization-timeout","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}