tonhowtf/omniget · error

X : resposta invalida ( )

Error message

X {}: resposta invalida ({})

What it means

After a successful HTTP status, check() parses the body as JSON; a serde failure raises 'X <op>: resposta invalida (<serde error>)', meaning X returned 2xx but the body is not valid JSON. It then also guards against a null/empty 'data' field as a separate no-data path.

Solutions

  1. Inspect the raw body — if it is HTML, X is challenging/blocking the client; slow down or authenticate.
  2. Log the first bytes of the response and the serde error to identify corruption or encoding issues.
  3. Ensure the request sets Accept: application/json and does not disable/miss decompression.
  4. Retry after backoff; challenge pages are often transient for flagged IPs.

Example fix

// before
let v: Value = serde_json::from_str(&text).map_err(|e| anyhow!("X {}: resposta invalida ({})", op, e))?;
// after
let v: Value = serde_json::from_str(&text).map_err(|e| {
    tracing::warn!(op, snippet = %text.chars().take(120).collect::<String>(), "non-JSON 2xx from X");
    anyhow!("X {}: resposta invalida ({})", op, e)
})?;
Defensive patterns

Strategy: try-catch

Type guard

fn is_json(text: &str) -> bool {
    serde_json::from_str::<serde_json::Value>(text).is_ok()
}

Try / catch

match gql(op).await {
    Err(e) if e.to_string().contains("resposta invalida") => {
        // body was not JSON: likely a challenge page
        slow_down_and_authenticate();
        Err(e)
    }
    other => other,
}

Prevention

When it happens

Trigger: check() getting a 2xx response whose body fails serde_json::from_str — HTML error/challenge pages, empty bodies, or BOM/compressed content mis-decoded as text.

Common situations: X serving an anti-bot challenge page with HTTP 200; captive portal or proxy injecting HTML; content-encoding mismatch causing garbled text.

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/4b01cfd7e3f6aec0. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/x/client.rs:322

            return Err(anyhow!("X_RATE_LIMIT:{}", reset));
        }
        let text = resp.text().await.unwrap_or_default();
        if status.as_u16() == 404 {
            return Ok(Err("not_found".into()));
        }
        if status.as_u16() == 401 || status.as_u16() == 403 {
            return Ok(Err(format!("auth:{}", status.as_u16())));
        }
        if !status.is_success() {
            return Err(anyhow!(
                "X {}: HTTP {} {}",
                op,
                status,
                text.chars().take(200).collect::<String>()
            ));
        }
        let v: Value = serde_json::from_str(&text)
            .map_err(|e| anyhow!("X {}: resposta invalida ({})", op, e))?;
        if v.get("data")
            .map(|d| d.is_null() || d.as_object().map(|o| o.is_empty()).unwrap_or(false))
            .unwrap_or(true)
        {
            if let Some(msg) = v
                .get("errors")
                .and_then(|e| e.as_array())
                .and_then(|a| a.first())
                .and_then(|e| e.get("message"))
                .and_then(|m| m.as_str())
            {
                if msg.contains("Query not found") || msg.contains("query_id") {
                    return Ok(Err("not_found".into()));
                }
                return Err(anyhow!("X {}: {}", op, msg));
            }
        }
        Ok(Ok(v))

View on GitHub (pinned to 8600b91f42)