tonhowtf/omniget · error · anyhow::Error

a API do TikTok respondeu HTTP

Error message

a API do TikTok respondeu HTTP {}

What it means

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.

Solutions

  1. Read the embedded status code: 401/403 → refresh cookies and session; 429 → back off and slow the request pacing.
  2. Re-export fresh tiktok.com cookies and retry after expiry or 403.
  3. Increase the delay between requests (pacer) or reduce limit to avoid rate limiting.
  4. Retry later for 5xx; if 403 persists with fresh cookies, TikTok's signing requirements changed and the library may need an update.

Example fix

// before
for _ in 0..200 { /* tight loop, no pacing beyond pacer.wait() */ }
// after
opts.limit = 30; // smaller batches
// increase pacer interval, e.g. pacer = Pacer::with_min_interval(Duration::from_secs(3));
Defensive patterns

Strategy: retry

Validate before calling

// Rust
// No pre-call check possible for server status; reduce risk by pacing:
let pacer = Pacer::with_min_interval(std::time::Duration::from_secs(3));
assert!(opts.limit <= 100, "limites altos aumentam chance de 429");

Try / catch

for attempt in 0..3 {
    match run(opts.clone()).await {
        Ok(v) => { render(v); break; }
        Err(e) if e.to_string().contains("HTTP 429") => tokio::time::sleep(Duration::from_secs(30 * (attempt + 1))).await,
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

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

Common situations: Expired cookies produce 403; running many rapid requests trips 429; TikTok changes its API signature requirements causing 403; temporary TikTok outage returns 5xx.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/tiktok/favorites.rs:389

            "não achei o secUid de @{} na página do perfil — a sessão pode ter expirado",
            handle
        )
    })?;

    let mut out: Vec<Entry> = Vec::new();
    let mut cursor = String::from("0");
    let teto = if opts.limit == 0 {
        u32::MAX
    } else {
        opts.limit
    };
    for _ in 0..200 {
        let url = item_list_url(&opts.source, &sec_uid, &cursor, 30)
            .ok_or_else(|| anyhow!("fonte desconhecida: {}", opts.source))?;
        pacer.wait().await;
        let resp = client.get(&url).header("Referer", &profile).send().await?;
        if !resp.status().is_success() {
            return Err(anyhow!("a API do TikTok respondeu HTTP {}", resp.status()));
        }
        let body = resp.text().await?;
        if body.trim().is_empty() {
            return Err(anyhow!(
                "a API do TikTok devolveu resposta vazia — normalmente é a sessão expirada ou a \
                 assinatura da requisição que o site passou a exigir"
            ));
        }
        let v: Value = serde_json::from_str(&body)
            .map_err(|_| anyhow!("a resposta da API do TikTok não era JSON"))?;
        let (page, next, has_more) = entries_from_item_list(&v);
        let vazio = page.is_empty();
        for e in page {
            if out.len() as u32 >= teto {
                break;
            }
            if !out.iter().any(|x| x.id == e.id) {
                out.push(e);

View on GitHub (pinned to 8600b91f42)