{"record":{"id":"401eef7e370cd88d","repo":"tonhowtf/omniget","slug":"failed-to-download-thumbnail","errorCode":null,"errorMessage":"Failed to download thumbnail: {}","messagePattern":"Failed to download thumbnail: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/ffmpeg.rs","lineNumber":579,"sourceCode":"    }\n    if !rename_ok {\n        let _ = std::fs::remove_file(&temp_output);\n        return Err(anyhow!(\"Failed to replace file\"));\n    }\n\n    Ok(())\n}\n\nasync fn download_thumbnail(\n    client: &reqwest::Client,\n    url: &str,\n    dest_dir: &Path,\n) -> anyhow::Result<std::path::PathBuf> {\n    let response = client\n        .get(url)\n        .send()\n        .await\n        .map_err(|e| anyhow!(\"Failed to download thumbnail: {}\", e))?;\n\n    let content_type = response\n        .headers()\n        .get(\"content-type\")\n        .and_then(|v| v.to_str().ok())\n        .unwrap_or(\"image/jpeg\")\n        .to_string();\n\n    let bytes = response\n        .bytes()\n        .await\n        .map_err(|e| anyhow!(\"Failed to read thumbnail: {}\", e))?;\n\n    let ext = if content_type.contains(\"png\") {\n        \"png\"\n    } else {\n        \"jpg\"\n    };","sourceCodeStart":561,"sourceCodeEnd":597,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/ffmpeg.rs#L561-L597","documentation":"download_thumbnail fetches a thumbnail image URL before embedding it with ffmpeg. When the reqwest GET fails to even complete (DNS failure, connection refused, TLS error, timeout), the code wraps the transport error with this message via anyhow. It indicates the HTTP request itself failed, not a bad status code.","triggerScenarios":"Calling embed_metadata -> download_thumbnail when the thumbnail host is unreachable, DNS fails, the URL scheme is unsupported, TLS handshake fails, or the request times out.","commonSituations":"Video host serves thumbnails from a different CDN that is blocked/offline; offline or proxied environment; thumbnail URL extracted with an expired signed token; misconfigured proxy blocking the request.","solutions":["Check network connectivity/DNS to the thumbnail host; test the URL in a browser or with curl.","Verify the thumbnail URL is valid and not expired; re-extract metadata if the URL contains a signature.","If a request timeout/proxy is involved, configure reqwest Client with proper timeout and proxy settings.","Make thumbnail embedding non-fatal: fall back to skipping thumbnail embed when download fails."],"exampleFix":"// before\nlet response = client.get(url).send().await\n    .map_err(|e| anyhow!(\"Failed to download thumbnail: {}\", e))?;\n// after\nlet response = match client.get(url).send().await {\n    Ok(r) => r,\n    Err(e) => {\n        log::warn!(\"thumbnail download failed, skipping embed: {e}\");\n        return Ok(None); // proceed without thumbnail\n    }\n};","handlingStrategy":"try-catch","validationCode":"// Rust: sanity-check the URL before requesting\nif !url.starts_with(\"http\") {\n    anyhow::bail!(\"invalid thumbnail url: {url}\");\n}\n// optionally: if tokio::net::lookup_host(host_port).await.is_err() { bail!(\"DNS failure\") }","typeGuard":null,"tryCatchPattern":"match client.get(url).send().await {\n    Ok(resp) => resp,\n    Err(e) => { log::warn!(\"thumb fetch failed: {e}\"); return Ok(None); } // degrade gracefully\n};","preventionTips":["Always attach a timeout and sensible User-Agent to the reqwest Client.","Treat thumbnail embedding as best-effort; never fail the whole job for it.","Re-extract thumbnail URLs close to use time; signed URLs expire.","Log the failing URL with the error to speed diagnosis."],"tags":["network","http","thumbnail","download"],"backgroundTag":"network-request-failed","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}