{"record":{"id":"10bb477dc05780eb","repo":"tonhowtf/omniget","slug":"a-autoriza-o-do-trakt-expirou-de-vez-conecte-a-conta-de-novo","errorCode":null,"errorMessage":"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)","messagePattern":"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\\)","errorType":"exception","errorClass":"anyhow","httpStatus":400,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/lists/trakt.rs","lineNumber":406,"sourceCode":"    let r = client()?\n        .post(format!(\"{}/oauth/token\", AUTH))\n        .json(&serde_json::json!({\n            \"refresh_token\": c.refresh_token,\n            \"client_id\": c.client_id,\n            \"client_secret\": c.client_secret,\n            \"redirect_uri\": \"urn:ietf:wg:oauth:2.0:oob\",\n            \"grant_type\": \"refresh_token\",\n        }))\n        .send()\n        .await?;\n    if !r.status().is_success() {\n        let status = r.status().as_u16();\n        let body = r.text().await.unwrap_or_default();\n        // O Trakt passou a invalidar o refresh token a cada uso, e a sessão\n        // antiga morre de vez: quando ele diz isso, não adianta insistir.\n        if status == 400 && body.contains(\"invalid_grant\") {\n            let _ = disconnect();\n            return Err(anyhow!(\n                \"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)\"\n            ));\n        }\n        // Fora isso não é fatal: o token atual ainda pode valer.\n        tracing::debug!(\"trakt: refresh recusado (HTTP {})\", status);\n        return Ok(());\n    }\n    let v: Value = r.json().await?;\n    save_token(&v)?;\n    let _g = LOCK.lock().unwrap_or_else(|e| e.into_inner());\n    *c = load();\n    Ok(())\n}\n\n// ── Leitura da API ──────────────────────────────────────────────────────\n\n/// Cliente autenticado com freio, no mesmo desenho do Reddit.\nstruct Api {","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/lists/trakt.rs#L388-L424","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["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)","Avoid running multiple instances that refresh the same token concurrently","Persist the refreshed tokens immediately after each successful refresh","If it keeps happening, check whether Trakt rotated policy on refresh-token reuse"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// check token age / last refresh time before issuing requests\nif last_refresh.elapsed() > MAX_SESSION_AGE {\n    proactively_reconnect().await?;\n}","typeGuard":null,"tryCatchPattern":"match run().await {\n    Err(e) if e.to_string().contains(\"expirou de vez\") => {\n        // launch the device-flow reconnect UX (device_code + wait_for_token)\n    }\n    other => other?,\n}","preventionTips":["Persist refreshed tokens immediately after every successful refresh","Never run multiple instances sharing the same Trakt token store","Treat any invalid_grant as terminal and re-run the device flow promptly"],"tags":["oauth","trakt","refresh-token","token-expired"],"backgroundTag":"jwt-token-expired","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"}