{"record":{"id":"d49d93f25bc514a9","repo":"wasmerio/wasmer","slug":"could-not-apply-request-header-name-value","errorCode":null,"errorMessage":"Could not apply request header: '{name}': '{value}'","messagePattern":"Could not apply request header: '(.+?)': '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/wasix/src/http/web_http_client.rs","lineNumber":201,"sourceCode":"            // is configured then try again with the cors proxy\n            let url = if let Some(cors_proxy) = cors_proxy {\n                format!(\"https://{}/{}\", cors_proxy, url)\n            } else {\n                return Err(js_error(e).context(format!(\"Could not fetch '{url}'\")));\n            };\n\n            let request = web_sys::Request::new_with_str_and_init(&url, &opts)\n                .map_err(js_error)\n                .with_context(|| format!(\"Could not construct request for url '{url}'\"))?;\n\n            let set_headers = request.headers();\n            for (name, val) in headers.iter() {\n                let value = String::from_utf8_lossy(val.as_bytes());\n                set_headers\n                    .set(name.as_str(), &value)\n                    .map_err(js_error)\n                    .with_context(|| {\n                        anyhow::anyhow!(\"Could not apply request header: '{name}': '{value}'\")\n                    })?;\n            }\n\n            call_fetch(&request)\n                .await\n                .map_err(js_error)\n                .with_context(|| format!(\"Could not fetch '{url}'\"))?\n        }\n    };\n\n    let response = resp_value.dyn_ref().unwrap();\n    read_response(response).await\n}\n\nasync fn read_response(response: &web_sys::Response) -> Result<HttpResponse, anyhow::Error> {\n    let status = http::StatusCode::from_u16(response.status())?;\n    let headers = headers(response.headers()).context(\"Unable to read the headers\")?;\n    let body = get_response_data(response).await?;","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/wasmerio/wasmer/blob/8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5/lib/wasix/src/http/web_http_client.rs#L183-L219","documentation":"In the browser/web HTTP client for WASIX, `fetch` copies each request header onto a JS `Headers`-like object via set(). If the JS side rejects a header (browser fetch forbids certain headers like Host, Content-Length, Connection; or invalid characters in name/value), js_error is turned into this context message naming the offending header. The request never reaches the network.","triggerScenarios":"A WASM module sets a forbidden or malformed header (e.g. Host, Content-Length, Connection, or a value containing non-ASCII/control characters) and the underlying JS set() throws.","commonSituations":"Ported native code that manually sets Host or Content-Length; user-supplied header values with newlines or unicode; forwarding an incoming request's full header map (including hop-by-hop headers) to a new fetch call.","solutions":["Remove forbidden headers before fetch: drop Host, Content-Length, Connection, Transfer-Encoding and similar from the request.","Sanitize header values: strip control characters and ensure UTF-8-safe ASCII values.","Only forward safe headers when proxying an inbound request (use an allowlist).","Check the inner js_error text — browsers list the exact rejected header.","If the header is genuinely required, move it to the server/proxy layer instead of the browser fetch."],"exampleFix":"// before\nfor (name, val) in headers.iter() {\n    let value = String::from_utf8_lossy(val.as_bytes());\n    set_headers.set(name.as_str(), &value).map_err(js_error)?;\n}\n// after: skip forbidden headers\nconst FORBIDDEN: &[&str] = &[\"host\", \"content-length\", \"connection\", \"transfer-encoding\"];\nfor (name, val) in headers.iter() {\n    if FORBIDDEN.contains(&name.as_str().to_ascii_lowercase().as_str()) { continue; }\n    let value: String = String::from_utf8_lossy(val.as_bytes())\n        .chars().filter(|c| !c.is_control()).collect();\n    set_headers.set(name.as_str(), &value).map_err(js_error)?;\n}","handlingStrategy":"validation","validationCode":"// filter forbidden/malformed headers before calling fetch\nconst FORBIDDEN: &[&str] = &[\"host\", \"content-length\", \"connection\", \"transfer-encoding\", \"keep-alive\"];\nfn is_safe_header(name: &str, value: &str) -> bool {\n    !FORBIDDEN.contains(&name.to_ascii_lowercase().as_str())\n        && value.chars().all(|c| !c.is_control())\n        && name.chars().all(|c| c.is_ascii_alphanumeric() || c == '-')\n}","typeGuard":null,"tryCatchPattern":"match spawn_fetch(req).await {\n    Err(e) if e.to_string().contains(\"Could not apply request header\") => {\n        eprintln!(\"{e}\\nHint: browsers forbid Host/Content-Length/Connection headers — strip them before fetch\");\n        std::process::exit(1);\n    }\n    other => other,\n}","preventionTips":["Never set browser-forbidden headers (Host, Content-Length, Connection) in fetch","Sanitize user-supplied header values: strip control chars and non-ASCII","Use an allowlist when forwarding inbound request headers to a new fetch","Test header-heavy workloads in the target JS environment (workers/polyfills differ)"],"tags":["http","headers","browser","javascript","wasm"],"backgroundTag":"forbidden-http-header","analyzedSha":"8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5","analyzedAt":"2026-09-01T23:06:31.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}