{"record":{"id":"367c21b4890e6abb","repo":"denoland/deno","slug":"empty-response-from-url","errorCode":null,"errorMessage":"empty response from {url}","messagePattern":"empty response from (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/tools/desktop.rs","lineNumber":1986,"sourceCode":"    let url = Url::parse(&laufey_release_url(&archive))?;\n    let progress_bar = ProgressBar::new(ProgressBarStyle::DownloadBars);\n    let progress = progress_bar.update(&archive);\n    // Send a real User-Agent — some CDNs (incl. parts of GitHub\n    // releases) start rate-limiting empty UAs aggressively.\n    let mut headers = http::HeaderMap::new();\n    if let Ok(ua) = http::HeaderValue::from_str(&format!(\n      \"deno-desktop/{} (+https://deno.com)\",\n      env!(\"CARGO_PKG_VERSION\")\n    )) {\n      headers.insert(http::header::USER_AGENT, ua);\n    }\n    let response = client\n      .download_with_progress_and_retries(url.clone(), &headers, &progress)\n      .await\n      .with_context(|| format!(\"failed to download {url}\"))?;\n    let data = response\n      .into_maybe_bytes()?\n      .ok_or_else(|| deno_core::anyhow::anyhow!(\"empty response from {url}\"))?;\n\n    let actual =\n      faster_hex::hex_string(&sha2::Sha256::digest(&data)).to_lowercase();\n    let expected_lc = expected.to_lowercase();\n    if actual != expected_lc {\n      // Include the URL in the bail: an attacker who poisoned a redirect\n      // would otherwise be invisible in the failure log.\n      bail!(\n        \"checksum mismatch for {archive} (downloaded from {url})\\n  expected: {expected_lc}\\n  actual:   {actual}\"\n      );\n    }\n\n    let parent = dir.parent().ok_or_else(|| {\n      deno_core::anyhow::anyhow!(\n        \"LAUFEY cache dir has no parent: {}\",\n        dir.display()\n      )\n    })?;","sourceCodeStart":1968,"sourceCodeEnd":2004,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/tools/desktop.rs#L1968-L2004","documentation":"After the laufey archive download completes (including retries), the HTTP response body is empty: into_maybe_bytes() returned Ok(None), i.e. the server sent a 2xx response with zero bytes. The downloader treats an empty body as a hard error because it cannot even attempt the SHA-256 comparison on zero bytes.","triggerScenarios":"GET of the laufey release URL via download_with_progress_and_retries returns 204 No Content or a 200 with an empty body — e.g. a misbehaving mirror, a corporate proxy that swallows the body, a redirect chain ending in an empty object store response, or a transient CDN failure after the final retry succeeded at the header level.","commonSituations":"Corporate HTTP(S) proxies or SSL-inspecting middleboxes that return empty bodies; a truncated object-storage response on a flaky connection; the release asset was yanked and the host now serves an empty 200; rare transient CDN glitch.","solutions":["Re-run the command — transient empty responses usually resolve on a fresh request.","Verify the URL from the error with curl -IL to confirm the asset exists and has a non-zero Content-Length.","Disable/inspect HTTP(S)_PROXY and NO_PROXY settings if a corporate proxy is in play, or exempt the release host.","If it reproduces consistently, capture the exact URL and response headers and report it — a persistent empty 200 for a pinned asset is an upstream host problem."],"exampleFix":"# before: opaque failure inside the tool\ndeno desktop\n# error: empty response from https://.../laufey-v1.2.3-x86_64-unknown-linux-gnu.tar.gz\n\n# after: triage the URL out-of-band, then retry\ncurl -IL 'https://.../laufey-v1.2.3-x86_64-unknown-linux-gnu.tar.gz'  # expect 200 + Content-Length > 0\ndeno desktop","handlingStrategy":"retry","validationCode":"# Probe the asset before launching the build; an empty/absent body shows up here\ncurl -fsSL -o /dev/null -w '%{http_code} %{size_download}\\n' \"$LAUFEY_ARCHIVE_URL\"\n# expect '200 <nonzero>'; anything else will fail inside deno too","typeGuard":null,"tryCatchPattern":"Catch download errors, inspect the context chain for 'empty response from', and retry with capped exponential backoff (2-3 attempts); an empty body from a CDN is overwhelmingly transient, unlike a checksum mismatch which must never be retried blindly.","preventionTips":["Keep the release host reachable without a body-mangling proxy (NO_PROXY for the artifact host).","Pre-warm/verify artifacts with a HEAD request in CI before invoking the desktop build.","Log the URL (the code already includes it) so retries can be correlated to specific CDN nodes."],"tags":["network","download","proxy","laufey"],"backgroundTag":"empty-http-response-body","analyzedSha":"f7822238cab635a3a19f99f493f675fa81a7f9d8","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}