tonhowtf/omniget · error

o Reddit respondeu algo que não é JSON

Error message

o Reddit respondeu algo que não é JSON ({}): {}

What it means

`get_json` fetches a Reddit URL and, on a 2xx response, parses the body with `serde_json::from_str`. When the body is not valid JSON (e.g. an HTML page, empty body, or interstitial), the parse error is wrapped in this message including the serde error and the URL. Reddit sometimes returns HTML (login walls, block pages) with a success status.

Solutions

  1. Print/log the raw body on failure to see what Reddit actually returned
  2. Ensure the URL points at the JSON API (e.g. append `.json` to Reddit post URLs)
  3. Disable or bypass proxies/VPNs that may inject HTML responses
  4. Set a proper User-Agent header, as Reddit may serve block pages without one
  5. Retry later — Reddit intermittently serves non-JSON interstitials under load

Example fix

// before
let url = "https://www.reddit.com/r/rust/comments/abc123";
let v = client.get_json(url).await?;
// after
let url = "https://www.reddit.com/r/rust/comments/abc123.json";
let v = client.get_json(url).await
    .map_err(|e| { eprintln!("non-JSON body from {url}: {e}"); e })?;
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: probe that the URL yields JSON before the real call
let head = client.get(&url).header("User-Agent", UA).send().await?;
let ct = head.headers().get("content-type").and_then(|v| v.to_str().ok()).unwrap_or("");
if !ct.contains("json") { return Err(format!("non-JSON content-type: {ct} for {url}")); }

Type guard

fn looks_like_json(body: &str) -> bool {
    let t = body.trim_start();
    t.starts_with('{') || t.starts_with('[')
}

Try / catch

match client.get_json(url).await {
    Ok(v) => v,
    Err(e) if e.to_string().contains("não é JSON") => {
        eprintln!("Reddit returned non-JSON for {url}; body likely HTML — check UA/proxy");
        fallback_value
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Any `get_json` call where Reddit returns HTTP 2xx but the body is not JSON: HTML error/blocked pages, empty bodies, rate-limit interstitials served with 200, or a proxy/captive portal intercepting the request.

Common situations: Corporate proxy or captive portal returning an HTML page with 200; Reddit serving login-required HTML for restricted content; calling an endpoint URL that no longer returns JSON; a misconstructed URL hitting the web UI instead of the JSON API.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/reddit/mod.rs:429

    /// GET com JSON de volta. Repete em 429 e em erro de servidor, e passa
    /// pelo desafio de JavaScript quando leva 403.
    pub async fn get_json(&self, url: &str) -> Result<serde_json::Value> {
        const TRIES: u32 = 4;
        let mut wait = Duration::from_secs(3);
        for attempt in 1..=TRIES {
            self.pace().await;
            self.requests.fetch_add(1, Ordering::Relaxed);
            let resp = self.client.get(url).send().await;
            match resp {
                Ok(r) if r.status().as_u16() == 403 && attempt < TRIES => {
                    let _ = r.text().await;
                    self.unlock().await?;
                }
                Ok(r) if r.status().is_success() => {
                    let text = r.text().await?;
                    return serde_json::from_str(&text).map_err(|e| {
                        anyhow!("o Reddit respondeu algo que não é JSON ({}): {}", e, url)
                    });
                }
                Ok(r) if r.status().as_u16() == 429 || r.status().is_server_error() => {
                    if attempt == TRIES {
                        return Err(anyhow!(
                            "o Reddit está limitando o acesso (HTTP {}). Tente de novo daqui a pouco",
                            r.status()
                        ));
                    }
                    let retry = r
                        .headers()
                        .get(reqwest::header::RETRY_AFTER)
                        .and_then(|v| v.to_str().ok())
                        .and_then(|v| v.trim().parse::<u64>().ok())
                        .map(Duration::from_secs);
                    tokio::time::sleep(retry.unwrap_or(wait)).await;
                    wait *= 2;
                }

View on GitHub (pinned to 8600b91f42)