{"record":{"id":"aec415307d2d45c7","repo":"Hmbown/CodeWhale","slug":"device-code","errorCode":null,"errorMessage":"{}","messagePattern":"\\{\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/device_code.rs","lineNumber":174,"sourceCode":"                    };\n                }\n            }\n\n            // Never sleep past the code's expiry, even after slow_down backoff.\n            let remaining = deadline.saturating_duration_since(Instant::now());\n            if remaining.is_zero() {\n                break;\n            }\n            sleep(interval.min(remaining));\n        }\n\n        Err(self.timed_out(saw_slow_down))\n    }\n\n    fn timed_out(&self, saw_slow_down: bool) -> anyhow::Error {\n        match (saw_slow_down, self.slow_down_timeout_message.as_deref()) {\n            (true, Some(message)) => anyhow::anyhow!(\"{message}\"),\n            _ => anyhow::anyhow!(\"{}\", self.timeout_message),\n        }\n    }\n}\n\n/// Reject a device-code verification URI that must not be handed to a browser\n/// opener.\n///\n/// Ported from pi's `validateVerificationUri`\n/// (`packages/ai/src/auth/oauth/xai.ts`, MIT, Copyright (c) 2025 Mario\n/// Zechner): the URI comes straight off the wire and is passed to the platform\n/// \"open this\" call, so a malicious or compromised response could otherwise\n/// launch `file:`, a custom app scheme, or a helper with attacker-chosen\n/// arguments. pi requires `https:`; Codewhale additionally allows `http:` on a\n/// loopback host, which is what self-hosted issuers and the device-code tests\n/// use — matching the loopback allowance the account login already makes.\n///\n/// Embedded credentials are rejected in every case.\npub fn validate_browser_verification_uri(raw: &str, context: &str) -> Result<String> {","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/config/src/device_code.rs#L156-L192","documentation":"The OAuth device-code polling loop (`DeviceCodePoller::run`) reached its lifetime deadline before the authorization flow completed, so it gives up with a timeout error. The message is the poller's configured `timeout_message`, or the `slow_down_timeout_message` instead when the server sent at least one `slow_down` response (a hint of client clock drift, e.g. in WSL/VMs). This is a deliberate terminal condition, not a transport failure.","triggerScenarios":"Calling `DeviceCodePoller::run(sleep, poll)` when the user never completes browser authorization (or the token endpoint keeps returning Pending/SlowDown) before `lifetime` elapses; also when `wait_before_first_poll` is set and the remaining lifetime is already zero.","commonSituations":"User abandons the login flow in the browser; user takes too long to enter the device code; system clock drifts badly inside WSL or a suspended VM causing repeated `slow_down` responses until the deadline passes; `lifetime` configured too short for slow users.","solutions":["Complete the device-code authorization in the browser promptly and restart the login flow.","Increase the poller's `lifetime` (builder setting) to give users more time.","If the slow_down-specific message appears, resync the system clock (e.g. restart WSL or run an NTP sync) and retry.","Check network access to the auth server so polls actually reach Pending/Complete instead of stalling."],"exampleFix":"// before\nDeviceCodePoller::new(endpoint).lifetime(Duration::from_secs(60))\n// after\nDeviceCodePoller::new(endpoint).lifetime(Duration::from_secs(600))","handlingStrategy":"try-catch","validationCode":"let lifetime = Duration::from_secs(600);\nassert!(lifetime > Duration::from_secs(60), \"device-code lifetime too short for interactive login\");","typeGuard":null,"tryCatchPattern":"match poller.run(sleep, poll) {\n    Err(err) if err.to_string().contains(\"timed out\") => eprintln!(\"Login not completed in time; rerun and authorize promptly.\"),\n    Err(err) => return Err(err),\n    Ok(token) => store(token),\n}","preventionTips":["Configure a generous lifetime (several minutes) for interactive logins.","Surface the verification URL prominently so users act quickly.","Watch for slow_down-shaped messages and prompt an NTP/clock resync in WSL/VM environments.","Treat this error as retryable: offer to restart the flow instead of failing hard."],"tags":["oauth","device-code","timeout","authentication"],"backgroundTag":"request-timeout","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}