tonhowtf/omniget · error · anyhow

Poll::Expired.message()

Error message

Poll::Expired.message()

What it means

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.

Solutions

  1. Restart the flow: call device_code() again to get a fresh code and expiry
  2. Prompt the user to enter the code at trakt.tv/activate promptly
  3. Increase Poll::SlowDown handling awareness — keep polling within the deadline
  4. If codes expire repeatedly, surface the user_code and verification_url earlier in the UI
Defensive patterns

Strategy: try-catch

Validate before calling

let deadline = Duration::from_secs(dc.expires_in.clamp(60, 1800));
// show the user a countdown so they activate before expiry

Try / catch

match wait_for_token(&dc, progress).await {
    Err(e) if e.to_string().contains(Poll::Expired.message()) => {
        // restart flow: let dc2 = device_code().await?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/c949f4e6eacea67e. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/lists/trakt.rs:307

/// Passo 2: consulta até o usuário liberar (ou o código morrer). Respeita o
/// intervalo pedido e recua quando leva 429.
pub async fn wait_for_token(dc: &DeviceCode, p: ProgressFn) -> Result<ConnectResult> {
    let c = {
        let _g = LOCK.lock().unwrap_or_else(|e| e.into_inner());
        load()
    };
    if c.client_secret.is_empty() {
        return Err(anyhow!(
            "o device flow precisa do client_secret da sua app do Trakt"
        ));
    }
    let http = client()?;
    let started = Instant::now();
    let deadline = Duration::from_secs(dc.expires_in.clamp(60, 1800));
    let mut interval = Duration::from_secs(dc.interval);
    loop {
        if started.elapsed() >= deadline {
            return Err(anyhow!("{}", Poll::Expired.message()));
        }
        tokio::time::sleep(interval).await;
        let left = deadline.saturating_sub(started.elapsed()).as_secs();
        report(
            &p,
            TOOL_ID,
            "progress",
            started.elapsed().as_secs(),
            Some(deadline.as_secs()),
            Some(format!("{} ({}s)", Poll::Pending.message(), left)),
        );
        let r = http
            .post(format!("{}/oauth/device/token", AUTH))
            .json(&serde_json::json!({
                "code": dc.device_code,
                "client_id": c.client_id,
                "client_secret": c.client_secret,
            }))

View on GitHub (pinned to 8600b91f42)