{"record":{"id":"c949f4e6eacea67e","repo":"tonhowtf/omniget","slug":"poll-expired-message","errorCode":null,"errorMessage":"Poll::Expired.message()","messagePattern":"Poll::Expired\\.message\\(\\)","errorType":"exception","errorClass":"anyhow","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/lists/trakt.rs","lineNumber":307,"sourceCode":"/// Passo 2: consulta até o usuário liberar (ou o código morrer). Respeita o\n/// intervalo pedido e recua quando leva 429.\npub async fn wait_for_token(dc: &DeviceCode, p: ProgressFn) -> Result<ConnectResult> {\n    let c = {\n        let _g = LOCK.lock().unwrap_or_else(|e| e.into_inner());\n        load()\n    };\n    if c.client_secret.is_empty() {\n        return Err(anyhow!(\n            \"o device flow precisa do client_secret da sua app do Trakt\"\n        ));\n    }\n    let http = client()?;\n    let started = Instant::now();\n    let deadline = Duration::from_secs(dc.expires_in.clamp(60, 1800));\n    let mut interval = Duration::from_secs(dc.interval);\n    loop {\n        if started.elapsed() >= deadline {\n            return Err(anyhow!(\"{}\", Poll::Expired.message()));\n        }\n        tokio::time::sleep(interval).await;\n        let left = deadline.saturating_sub(started.elapsed()).as_secs();\n        report(\n            &p,\n            TOOL_ID,\n            \"progress\",\n            started.elapsed().as_secs(),\n            Some(deadline.as_secs()),\n            Some(format!(\"{} ({}s)\", Poll::Pending.message(), left)),\n        );\n        let r = http\n            .post(format!(\"{}/oauth/device/token\", AUTH))\n            .json(&serde_json::json!({\n                \"code\": dc.device_code,\n                \"client_id\": c.client_id,\n                \"client_secret\": c.client_secret,\n            }))","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/lists/trakt.rs#L289-L325","documentation":"Thrown by wait_for_token when the polling loop exceeds the deadline derived from dc.expires_in (clamped to 60–1800s). The user never authorized the code at trakt.tv/activate within the expiry window, so Trakt's Poll::Expired variant is surfaced as an anyhow error.","triggerScenarios":"wait_for_token() polls /oauth/device/token until started.elapsed() >= deadline without ever receiving a success response — the user never entered the user_code before it expired.","commonSituations":"User ignored/closed the activation prompt, entered the code too late, the code expired while the machine was asleep, or interval polling kept getting SlowDown-ed past the deadline.","solutions":["Restart the flow: call device_code() again to get a fresh code and expiry","Prompt the user to enter the code at trakt.tv/activate promptly","Increase Poll::SlowDown handling awareness — keep polling within the deadline","If codes expire repeatedly, surface the user_code and verification_url earlier in the UI"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"let deadline = Duration::from_secs(dc.expires_in.clamp(60, 1800));\n// show the user a countdown so they activate before expiry","typeGuard":null,"tryCatchPattern":"match wait_for_token(&dc, progress).await {\n    Err(e) if e.to_string().contains(Poll::Expired.message()) => {\n        // restart flow: let dc2 = device_code().await?;\n    }\n    other => other?,\n}","preventionTips":["Show the user_code and trakt.tv/activate URL prominently with a countdown","Restart the flow automatically on expiry instead of failing silently","Wake/keep the device active during the polling window"],"tags":["oauth","trakt","timeout","device-flow"],"backgroundTag":"request-timeout","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}