{"record":{"id":"4967abedfed205ae","repo":"zed-industries/zed","slug":"failed-to-fetch-url-status-code","errorCode":null,"errorMessage":"failed to fetch '{url}': status code {}","messagePattern":"failed to fetch '(.+?)': status code (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs","lineNumber":312,"sourceCode":"    async fn which(\n        &mut self,\n        delegate: Resource<Arc<dyn WorktreeDelegate>>,\n        binary_name: String,\n    ) -> wasmtime::Result<Option<String>> {\n        latest::HostWorktree::which(self, delegate, binary_name).await\n    }\n\n    async fn drop(&mut self, _worktree: Resource<Worktree>) -> wasmtime::Result<()> {\n        // We only ever hand out borrows of worktrees.\n        Ok(())\n    }\n}\n\nimpl common::Host for WasmState {}\n\nimpl http_client::Host for WasmState {\n    async fn fetch(\n        &mut self,\n        request: http_client::HttpRequest,\n    ) -> wasmtime::Result<Result<http_client::HttpResponse, String>> {\n        maybe!(async {\n            let url = &request.url;\n            let request = convert_request(&request)?;\n            let mut response = self.host.http_client.send(request).await?;\n\n            if response.status().is_client_error() || response.status().is_server_error() {\n                bail!(\"failed to fetch '{url}': status code {}\", response.status())\n            }\n            convert_response(&mut response).await\n        })\n        .await\n        .to_wasmtime_result()\n    }\n\n    async fn fetch_stream(\n        &mut self,","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/zed-industries/zed/blob/5a9b9558db01a6b906cec2fb70a797affdc58cdd/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs#L294-L330","documentation":"Thrown by Zed's WebAssembly extension host (v0.1.0 WIT bindings) when an extension calls http_client::fetch and the server responds with a 4xx or 5xx status. The host deliberately converts any non-success HTTP status into an error string instead of returning the response, because the v0.1.0 WIT HttpResponse type has no way to carry an error body. Note that fetch_stream does NOT bail this way, so error responses with bodies must go through that API.","triggerScenarios":"A v0.1.0 extension calling http_client::fetch against a URL that returns 404, 401, 403, 500, 502, etc. The bail fires inside the maybe! block when response.status().is_client_error() || response.status().is_server_error().","commonSituations":"Extension downloading a release asset from a moved/renamed GitHub URL, hitting an API rate limit (403/429), an expired pre-signed S3 link, a typo in the download URL, a proxy returning 502, or auth missing for a private repo.","solutions":["Verify the exact URL the extension requests (it is echoed in the message) in a browser or with curl -I","Handle 4xx/5xx bodies by switching to fetch_stream, which returns the response regardless of status","For auth failures, supply the needed token/header in HttpRequest headers or use a public URL","For rate limits, retry with backoff or use a conditional/etag-aware endpoint"],"exampleFix":"// before\nlet response = http_client::fetch(&request).await?; // Err(\"failed to fetch '...': status code 404 Not Found\")\n\n// after — read error bodies via fetch_stream\nlet stream = http_client::fetch_stream(&request).await?;\nlet response = stream.next().await; // status + body available even for 4xx/5xx","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// extension side: fetch returns Result<HttpResponse, String>\nmatch http_client::fetch(&request).await {\n    Ok(response) => { /* 2xx/3xx only */ }\n    Err(e) if e.contains(\"status code\") => {\n        // non-2xx: surface URL+status, fall back to cached asset or retry for 5xx\n    }\n    Err(e) => return Err(e), // transport-level failure\n}","preventionTips":["Prefer fetch_stream when you need error bodies or status codes","Cache downloaded artifacts keyed by URL so 404/403s degrade gracefully","Log the URL from the error message before retrying so bad links are caught early"],"tags":["network","http","wasm","extension","zed"],"backgroundTag":"http-error-status","analyzedSha":"5a9b9558db01a6b906cec2fb70a797affdc58cdd","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}