{"record":{"id":"4e09321b39e5eefb","repo":"tonhowtf/omniget","slug":"libretranslate-resposta-invalida","errorCode":null,"errorMessage":"LibreTranslate: resposta invalida ({})","messagePattern":"LibreTranslate: resposta invalida \\((.+?)\\)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/srt_translate.rs","lineNumber":144,"sourceCode":"    opts: &TranslateOptions,\n) -> anyhow::Result<Vec<Option<String>>> {\n    let client = super::client()?;\n    let url = format!(\"{}/translate\", base_url.trim_end_matches('/'));\n    let mut body = serde_json::json!({\n        \"q\": lines,\n        \"source\": if opts.source_lang.is_empty() { \"auto\" } else { opts.source_lang.as_str() },\n        \"target\": opts.target_lang,\n        \"format\": \"text\",\n    });\n    if !api_key.is_empty() {\n        body[\"api_key\"] = serde_json::Value::String(api_key.to_string());\n    }\n    let resp = client.post(&url).json(&body).send().await?;\n    let status = resp.status();\n    let v: serde_json::Value = resp\n        .json()\n        .await\n        .map_err(|e| anyhow!(\"LibreTranslate: resposta invalida ({})\", e))?;\n    if !status.is_success() {\n        return Err(anyhow!(\n            \"LibreTranslate: HTTP {} {}\",\n            status.as_u16(),\n            v[\"error\"].as_str().unwrap_or(\"\")\n        ));\n    }\n    let out = match &v[\"translatedText\"] {\n        serde_json::Value::Array(a) => a\n            .iter()\n            .map(|x| x.as_str().map(|s| s.to_string()))\n            .collect(),\n        serde_json::Value::String(s) => vec![Some(s.clone())],\n        _ => vec![None; lines.len()],\n    };\n    Ok(out)\n}\n","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/srt_translate.rs#L126-L162","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: any non-JSON body falls through to json() and fails opaquely\nlet v: serde_json::Value = resp.json().await\n    .map_err(|e| anyhow!(\"LibreTranslate: resposta invalida ({})\", e))?;\n// after: capture status and raw body for a diagnosable error\nlet status = resp.status();\nlet raw = resp.text().await.map_err(|e| anyhow!(\"LibreTranslate: leitura falhou ({})\", e))?;\nlet v: serde_json::Value = serde_json::from_str(&raw)\n    .with_context(|| format!(\"LibreTranslate: resposta invalida (status {}, corpo: {:.200})\", status, raw))?;","handlingStrategy":"try-catch","validationCode":"// Probe the endpoint before translating\nlet health = client.post(&url).json(&serde_json::json!({\n    \"q\": \"hi\", \"source\": \"en\", \"target\": \"pt\"\n})).send().await?;\nlet ct_ok = health.headers().get(\"content-type\")\n    .map(|v| v.to_str().unwrap_or(\"\").contains(\"json\")).unwrap_or(false);\nif !ct_ok { return Err(anyhow!(\"endpoint nao retorna JSON: verifique a URL do LibreTranslate\")); }","typeGuard":"fn is_json_response(resp: &reqwest::Response) -> bool {\n    resp.headers().get(reqwest::header::CONTENT_TYPE)\n        .and_then(|v| v.to_str().ok())\n        .map(|ct| ct.contains(\"application/json\"))\n        .unwrap_or(false)\n}","tryCatchPattern":"match translate_cues(...).await {\n    Ok(cues) => cues,\n    Err(e) if e.to_string().contains(\"resposta invalida\") => {\n        eprintln!(\"Resposta nao-JSON do LibreTranslate; verifique URL/proxy: {e}\");\n        fallback_translate(cues)?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["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"],"tags":["http","json","rust","network","translation"],"backgroundTag":"invalid-json-response","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}