tonhowtf/omniget · error · anyhow

a autorização do Trakt expirou de vez. Conecte a conta de…

Error message

a autorização do Trakt expirou de vez. Conecte a conta de novo (o código aparece aqui e você libera em trakt.tv/activate)

What it means

Thrown by refresh_if_needed when Trakt responds HTTP 400 with 'invalid_grant' to the refresh-token request, meaning the refresh token has been invalidated permanently. The code calls disconnect() to clear the stored session and instructs the user to reconnect via the device flow again.

Solutions

  1. Reconnect the account: run device_code() and wait_for_token() to get a brand-new session (as the message says, code appears in-app and is activated at trakt.tv/activate)
  2. Avoid running multiple instances that refresh the same token concurrently
  3. Persist the refreshed tokens immediately after each successful refresh
  4. If it keeps happening, check whether Trakt rotated policy on refresh-token reuse
Defensive patterns

Strategy: retry

Validate before calling

// check token age / last refresh time before issuing requests
if last_refresh.elapsed() > MAX_SESSION_AGE {
    proactively_reconnect().await?;
}

Try / catch

match run().await {
    Err(e) if e.to_string().contains("expirou de vez") => {
        // launch the device-flow reconnect UX (device_code + wait_for_token)
    }
    other => other?,
}

Prevention

When it happens

Trigger: POSTing the refresh token to Trakt's token endpoint yields 400 invalid_grant — the refresh token was revoked/expired/already used (the source comment notes Trakt now invalidates refresh tokens on each use and old sessions die).

Common situations: Long-lived sessions where the refresh token was rotated or invalidated server-side; running two instances sharing one Trakt account so a refresh consumes the token; token store out of sync after manual config edits.

Related errors


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

Appendix: source

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

    let r = client()?
        .post(format!("{}/oauth/token", AUTH))
        .json(&serde_json::json!({
            "refresh_token": c.refresh_token,
            "client_id": c.client_id,
            "client_secret": c.client_secret,
            "redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
            "grant_type": "refresh_token",
        }))
        .send()
        .await?;
    if !r.status().is_success() {
        let status = r.status().as_u16();
        let body = r.text().await.unwrap_or_default();
        // O Trakt passou a invalidar o refresh token a cada uso, e a sessão
        // antiga morre de vez: quando ele diz isso, não adianta insistir.
        if status == 400 && body.contains("invalid_grant") {
            let _ = disconnect();
            return Err(anyhow!(
                "a autorização do Trakt expirou de vez. Conecte a conta de novo (o código aparece aqui e você libera em trakt.tv/activate)"
            ));
        }
        // Fora isso não é fatal: o token atual ainda pode valer.
        tracing::debug!("trakt: refresh recusado (HTTP {})", status);
        return Ok(());
    }
    let v: Value = r.json().await?;
    save_token(&v)?;
    let _g = LOCK.lock().unwrap_or_else(|e| e.into_inner());
    *c = load();
    Ok(())
}

// ── Leitura da API ──────────────────────────────────────────────────────

/// Cliente autenticado com freio, no mesmo desenho do Reddit.
struct Api {

View on GitHub (pinned to 8600b91f42)