{"record":{"id":"550b16cf707d7cae","repo":"tonhowtf/omniget","slug":"a-api-do-tiktok-respondeu-http","errorCode":null,"errorMessage":"a API do TikTok respondeu HTTP {}","messagePattern":"a API do TikTok respondeu HTTP (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/tiktok/favorites.rs","lineNumber":389,"sourceCode":"            \"não achei o secUid de @{} na página do perfil — a sessão pode ter expirado\",\n            handle\n        )\n    })?;\n\n    let mut out: Vec<Entry> = Vec::new();\n    let mut cursor = String::from(\"0\");\n    let teto = if opts.limit == 0 {\n        u32::MAX\n    } else {\n        opts.limit\n    };\n    for _ in 0..200 {\n        let url = item_list_url(&opts.source, &sec_uid, &cursor, 30)\n            .ok_or_else(|| anyhow!(\"fonte desconhecida: {}\", opts.source))?;\n        pacer.wait().await;\n        let resp = client.get(&url).header(\"Referer\", &profile).send().await?;\n        if !resp.status().is_success() {\n            return Err(anyhow!(\"a API do TikTok respondeu HTTP {}\", resp.status()));\n        }\n        let body = resp.text().await?;\n        if body.trim().is_empty() {\n            return Err(anyhow!(\n                \"a API do TikTok devolveu resposta vazia — normalmente é a sessão expirada ou a \\\n                 assinatura da requisição que o site passou a exigir\"\n            ));\n        }\n        let v: Value = serde_json::from_str(&body)\n            .map_err(|_| anyhow!(\"a resposta da API do TikTok não era JSON\"))?;\n        let (page, next, has_more) = entries_from_item_list(&v);\n        let vazio = page.is_empty();\n        for e in page {\n            if out.len() as u32 >= teto {\n                break;\n            }\n            if !out.iter().any(|x| x.id == e.id) {\n                out.push(e);","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/tiktok/favorites.rs#L371-L407","documentation":"list_private() checks the HTTP status of each item-list API response and fails with this anyhow error when the status is not a success (2xx). It surfaces TikTok's server-side rejection (auth, rate limiting, bot detection) with the exact status code for diagnosis.","triggerScenarios":"Any paginated request in the loop that returns 401/403 (session or signature rejected), 429 (rate limited), 5xx (TikTok server error), or redirects to a non-2xx error page.","commonSituations":"Expired cookies produce 403; running many rapid requests trips 429; TikTok changes its API signature requirements causing 403; temporary TikTok outage returns 5xx.","solutions":["Read the embedded status code: 401/403 → refresh cookies and session; 429 → back off and slow the request pacing.","Re-export fresh tiktok.com cookies and retry after expiry or 403.","Increase the delay between requests (pacer) or reduce limit to avoid rate limiting.","Retry later for 5xx; if 403 persists with fresh cookies, TikTok's signing requirements changed and the library may need an update."],"exampleFix":"// before\nfor _ in 0..200 { /* tight loop, no pacing beyond pacer.wait() */ }\n// after\nopts.limit = 30; // smaller batches\n// increase pacer interval, e.g. pacer = Pacer::with_min_interval(Duration::from_secs(3));","handlingStrategy":"retry","validationCode":"// Rust\n// No pre-call check possible for server status; reduce risk by pacing:\nlet pacer = Pacer::with_min_interval(std::time::Duration::from_secs(3));\nassert!(opts.limit <= 100, \"limites altos aumentam chance de 429\");","typeGuard":null,"tryCatchPattern":"for attempt in 0..3 {\n    match run(opts.clone()).await {\n        Ok(v) => { render(v); break; }\n        Err(e) if e.to_string().contains(\"HTTP 429\") => tokio::time::sleep(Duration::from_secs(30 * (attempt + 1))).await,\n        Err(e) => return Err(e),\n    }\n}","preventionTips":["Keep request pacing generous and limits modest to avoid 429.","Refresh cookies proactively; 401/403 usually means expired session.","Avoid running many parallel scrapes from the same IP.","Retry with exponential backoff on 5xx."],"tags":["tiktok","http","api-error","rate-limit","rust"],"backgroundTag":"http-error-response","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}