{"record":{"id":"b268ddd9c5bddbca","repo":"neondatabase/neon","slug":"download-gcs-object","errorCode":null,"errorMessage":"download gcs object","messagePattern":"download gcs object","errorType":"exception","errorClass":"DownloadError","httpStatus":null,"severity":"error","filePath":"libs/remote_storage/src/gcs_bucket.rs","lineNumber":745,"sourceCode":"        };\n\n        let resp = match obj_metadata {\n            Ok(resp) => {\n                if !resp.status().is_success() {\n                    match resp.status() {\n                        StatusCode::NOT_FOUND => return Err(DownloadError::NotFound),\n                        _ => {\n                            return Err(DownloadError::Other(anyhow::anyhow!(\n                                \"GCS GET response contained no response body\"\n                            )));\n                        }\n                    }\n                } else {\n                    resp\n                }\n            }\n            _ => {\n                return Err(DownloadError::Other(anyhow::anyhow!(\"download gcs object\")));\n            }\n        };\n\n        let body = resp\n            .text()\n            .await\n            .map_err(|e: reqwest::Error| DownloadError::Other(e.into()))?;\n\n        let resp: GCSObject = serde_json::from_str(&body)\n            .map_err(|e: serde_json::Error| DownloadError::Other(e.into()))?;\n\n        // 2. Byte Stream request\n        let mut headers = header::HeaderMap::new();\n        let bytes_range = match &request.range {\n           Some(s) => header::HeaderValue::from_str(s).unwrap(),\n           None => header::HeaderValue::from_static(\"bytes=0-\"),\n        };\n        ","sourceCodeStart":727,"sourceCodeEnd":763,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/remote_storage/src/gcs_bucket.rs#L727-L763","documentation":"The catch-all arm after the metadata GET in download(): it fires when the request itself failed at the reqwest transport layer (connection error, DNS failure, TLS error, request build/send error) rather than returning an HTTP response. The message 'download gcs object' is uninformative because the underlying reqwest::Error is dropped instead of being chained into the context.","triggerScenarios":"Network-level failure of the metadata GET: connection refused/reset, DNS resolution failure, TLS handshake error, or proxy misconfiguration — the select! resolves to Err(reqwest::Error) and the arm returns a bare message.","commonSituations":"Egress/DNS problems in the cluster; HTTP(S)_PROXY misconfiguration; connection resets under heavy load; transient network partitions to storage.googleapis.com.","solutions":["Check connectivity to storage.googleapis.com from the affected host (curl -v)","Retry — transport errors are usually transient","Patch or upstream a fix so the error is chained: anyhow::Error::new(e).context(\\\"download gcs object\\\") — the cause then becomes visible","Enable reqwest/hyper tracing (RUST_LOG=hyper=trace,reqwest=debug) to see the transport-level cause"],"exampleFix":"// before: underlying reqwest::Error dropped, only a bare string survives\n_ => {\n    return Err(DownloadError::Other(anyhow::anyhow!(\"download gcs object\")));\n}\n\n// after: chain the cause\nErr(e) => {\n    return Err(DownloadError::Other(\n        anyhow::Error::new(e).context(\"download gcs object\"),\n    ));\n}","handlingStrategy":"retry","validationCode":"// Cheap connectivity pre-flight when this error recurs in an environment.\nasync fn gcs_reachable() -> bool {\n    tokio::net::TcpStream::connect(\"storage.googleapis.com:443\").await.is_ok()\n}","typeGuard":null,"tryCatchPattern":"// Transport-level failure: backoff retry; the dropped reqwest::Error means logging context matters.\nlet download = backoff_retry(\n    || storage.download(from, &cancel),\n    |e| !matches!(e, DownloadError::NotFound | DownloadError::Cancelled),\n    3,\n    \"gcs download\",\n    cancel,\n).await;","preventionTips":["Verify DNS/egress/proxy configuration for storage.googleapis.com on affected hosts","Do not treat transport errors as object-level failures (e.g. don't mark data missing)","Chain underlying errors when patching: Error::new(e).context(...) preserves the cause for next time"],"tags":["gcs","google-cloud-storage","network","transport-error","error-context"],"backgroundTag":"network-request-failed","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}