tonhowtf/omniget · error
LibreTranslate: resposta invalida ({})
Error message
LibreTranslate: resposta invalida ({}) What it means
This error is thrown by translate_batch_libre when the HTTP response body returned by a LibreTranslate server cannot be parsed as JSON. The library uses anyhow! to wrap the serde_json parse error, so the original deserialization message appears inside the parentheses. It indicates the server replied with something other than the expected JSON payload (e.g. HTML, empty body, or a proxy error page).
Solutions
- Verify the endpoint URL points at the JSON API route (e.g. http://host:5000/translate), not the web UI root
- Open the endpoint with curl -X POST -H 'Content-Type: application/json' -d '{...}' to inspect the raw body and confirm it is JSON
- Check any reverse proxy in front of LibreTranslate; ensure it passes the request through instead of serving HTML error pages
- Increase client timeout/limits or retry, in case the body was truncated mid-transfer
- Check LibreTranslate server logs for crashes (OOM kill, API key requirement redirect) and restart/upgrade it
Example fix
// before: any non-JSON body falls through to json() and fails opaquely
let v: serde_json::Value = resp.json().await
.map_err(|e| anyhow!("LibreTranslate: resposta invalida ({})", e))?;
// after: capture status and raw body for a diagnosable error
let status = resp.status();
let raw = resp.text().await.map_err(|e| anyhow!("LibreTranslate: leitura falhou ({})", e))?;
let v: serde_json::Value = serde_json::from_str(&raw)
.with_context(|| format!("LibreTranslate: resposta invalida (status {}, corpo: {:.200})", status, raw))?; Defensive patterns
Strategy: try-catch
Validate before calling
// Probe the endpoint before translating
let health = client.post(&url).json(&serde_json::json!({
"q": "hi", "source": "en", "target": "pt"
})).send().await?;
let ct_ok = health.headers().get("content-type")
.map(|v| v.to_str().unwrap_or("").contains("json")).unwrap_or(false);
if !ct_ok { return Err(anyhow!("endpoint nao retorna JSON: verifique a URL do LibreTranslate")); } Type guard
fn is_json_response(resp: &reqwest::Response) -> bool {
resp.headers().get(reqwest::header::CONTENT_TYPE)
.and_then(|v| v.to_str().ok())
.map(|ct| ct.contains("application/json"))
.unwrap_or(false)
} Try / catch
match translate_cues(...).await {
Ok(cues) => cues,
Err(e) if e.to_string().contains("resposta invalida") => {
eprintln!("Resposta nao-JSON do LibreTranslate; verifique URL/proxy: {e}");
fallback_translate(cues)?
}
Err(e) => return Err(e),
} Prevention
- Point the client at the JSON API route (/translate), never the web UI root
- Health-check the endpoint and assert Content-Type: application/json before batch jobs
- Check reverse-proxy configs for HTML error pages (502/503) reaching the client
- Add a timeout and retry with backoff for truncated responses
When it happens
Trigger: Calling translate_cues with a LibreTranslate endpoint whose response body is not valid JSON: server down and returning an HTML error page, a reverse proxy (nginx/Cloudflare) intercepting the request, a wrong URL path hitting a non-API route, or a truncated/gzip response the client cannot decode.
Common situations: Self-hosted LibreTranslate behind a misconfigured reverse proxy; pointing the endpoint at the web UI URL instead of /translate; API gateway returning 502/503 HTML pages; LibreTranslate shutting down mid-request due to OOM; corporate proxy injecting an HTML block page.
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
- LibreTranslate: HTTP {} {}
- HTTP {}
- download de {} falhou: HTTP {}
- nao foi possivel buscar {}: {}
- HTTP {} downloading {}
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/4e09321b39e5eefb.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/tools/srt_translate.rs:144
opts: &TranslateOptions,
) -> anyhow::Result<Vec<Option<String>>> {
let client = super::client()?;
let url = format!("{}/translate", base_url.trim_end_matches('/'));
let mut body = serde_json::json!({
"q": lines,
"source": if opts.source_lang.is_empty() { "auto" } else { opts.source_lang.as_str() },
"target": opts.target_lang,
"format": "text",
});
if !api_key.is_empty() {
body["api_key"] = serde_json::Value::String(api_key.to_string());
}
let resp = client.post(&url).json(&body).send().await?;
let status = resp.status();
let v: serde_json::Value = resp
.json()
.await
.map_err(|e| anyhow!("LibreTranslate: resposta invalida ({})", e))?;
if !status.is_success() {
return Err(anyhow!(
"LibreTranslate: HTTP {} {}",
status.as_u16(),
v["error"].as_str().unwrap_or("")
));
}
let out = match &v["translatedText"] {
serde_json::Value::Array(a) => a
.iter()
.map(|x| x.as_str().map(|s| s.to_string()))
.collect(),
serde_json::Value::String(s) => vec![Some(s.clone())],
_ => vec![None; lines.len()],
};
Ok(out)
}
View on GitHub (pinned to 8600b91f42)