wasmerio/wasmer · error
Could not apply request header: '{name}': '{value}'
Error message
Could not apply request header: '{name}': '{value}' What it means
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.
Source
Thrown at lib/wasix/src/http/web_http_client.rs:201
// is configured then try again with the cors proxy
let url = if let Some(cors_proxy) = cors_proxy {
format!("https://{}/{}", cors_proxy, url)
} else {
return Err(js_error(e).context(format!("Could not fetch '{url}'")));
};
let request = web_sys::Request::new_with_str_and_init(&url, &opts)
.map_err(js_error)
.with_context(|| format!("Could not construct request for url '{url}'"))?;
let set_headers = request.headers();
for (name, val) in headers.iter() {
let value = String::from_utf8_lossy(val.as_bytes());
set_headers
.set(name.as_str(), &value)
.map_err(js_error)
.with_context(|| {
anyhow::anyhow!("Could not apply request header: '{name}': '{value}'")
})?;
}
call_fetch(&request)
.await
.map_err(js_error)
.with_context(|| format!("Could not fetch '{url}'"))?
}
};
let response = resp_value.dyn_ref().unwrap();
read_response(response).await
}
async fn read_response(response: &web_sys::Response) -> Result<HttpResponse, anyhow::Error> {
let status = http::StatusCode::from_u16(response.status())?;
let headers = headers(response.headers()).context("Unable to read the headers")?;
let body = get_response_data(response).await?;View on GitHub (pinned to 8c4b9ee9d3)
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.
Example fix
// before
for (name, val) in headers.iter() {
let value = String::from_utf8_lossy(val.as_bytes());
set_headers.set(name.as_str(), &value).map_err(js_error)?;
}
// after: skip forbidden headers
const FORBIDDEN: &[&str] = &["host", "content-length", "connection", "transfer-encoding"];
for (name, val) in headers.iter() {
if FORBIDDEN.contains(&name.as_str().to_ascii_lowercase().as_str()) { continue; }
let value: String = String::from_utf8_lossy(val.as_bytes())
.chars().filter(|c| !c.is_control()).collect();
set_headers.set(name.as_str(), &value).map_err(js_error)?;
} Defensive patterns
Strategy: validation
Validate before calling
// filter forbidden/malformed headers before calling fetch
const FORBIDDEN: &[&str] = &["host", "content-length", "connection", "transfer-encoding", "keep-alive"];
fn is_safe_header(name: &str, value: &str) -> bool {
!FORBIDDEN.contains(&name.to_ascii_lowercase().as_str())
&& value.chars().all(|c| !c.is_control())
&& name.chars().all(|c| c.is_ascii_alphanumeric() || c == '-')
} Try / catch
match spawn_fetch(req).await {
Err(e) if e.to_string().contains("Could not apply request header") => {
eprintln!("{e}\nHint: browsers forbid Host/Content-Length/Connection headers — strip them before fetch");
std::process::exit(1);
}
other => other,
} Prevention
- 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)
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unable to cast to a {}
- Exception handling is not yet supported in js
- Timeout while downloading response body
- cloning JavaScript shared memory should not fail
- unimplemented operator {operator:?}
AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01).
Data as JSON: /api/errors/d49d93f25bc514a9.
Report an issue: GitHub.