tonhowtf/omniget · error · anyhow::Error

a API do TikTok devolveu resposta vazia — normalmente é a…

Error message

a API do TikTok devolveu resposta vazia — normalmente é a sessão expirada ou a assinatura da requisição que o site passou a exigir

What it means

list_private() treats an empty body from the item-list API as fatal and raises this anyhow error, because TikTok normally returns JSON even for empty pages. An empty response almost always indicates the session was rejected or TikTok now requires request signing the client did not provide.

Solutions

  1. Re-export fresh cookies from a fully logged-in tiktok.com session and retry.
  2. Disable VPN/proxy or use a residential connection — datacenter IPs often get empty anti-bot responses.
  3. Retry after a delay; intermittent anti-bot checks often clear.
  4. If persistent, TikTok's signing requirements changed — update the library or its request signing logic.
Defensive patterns

Strategy: retry

Try / catch

match run(opts).await {
    Ok(entries) => render(entries),
    Err(e) if e.to_string().contains("resposta vazia") => {
        eprintln!("Sessão recusada ou anti-bot — reexporte cookies e tente de outro IP");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: The GET to the item-list endpoint succeeds with 2xx but the body is empty/whitespace — typically on the first page with expired-but-accepted cookies, anti-bot interception returning 200 with no body, or a proxy/VPN stripping the response.

Common situations: Cookies valid enough to pass status checks but insufficient for data (partial login), TikTok A/B serving an empty page to unsigned requests, corporate proxy or VPN interference.

Related errors


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

Appendix: source

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

    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);
            }
        }
        report(
            progress,

View on GitHub (pinned to 8600b91f42)