{"record":{"id":"c02934bd4ad98f0f","repo":"seanmonstar/reqwest","slug":"err","errorCode":null,"errorMessage":"{err}","messagePattern":"\\{err\\}","errorType":"exception","errorClass":"js_sys::Error","httpStatus":null,"severity":"error","filePath":"src/error.rs","lineNumber":324,"sourceCode":"}\n\nimpl StdError for Error {\n    fn source(&self) -> Option<&(dyn StdError + 'static)> {\n        self.inner.source.as_ref().map(|e| &**e as _)\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))]\nimpl From<crate::error::Error> for wasm_bindgen::JsValue {\n    fn from(err: Error) -> wasm_bindgen::JsValue {\n        js_sys::Error::from(err).into()\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))]\nimpl From<crate::error::Error> for js_sys::Error {\n    fn from(err: Error) -> js_sys::Error {\n        js_sys::Error::new(&format!(\"{err}\"))\n    }\n}\n\n#[derive(Debug)]\npub(crate) enum Kind {\n    Builder,\n    Request,\n    Redirect,\n    #[cfg(not(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\"))))]\n    Status(StatusCode, Option<hyper::ext::ReasonPhrase>),\n    #[cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))]\n    Status(StatusCode),\n    Body,\n    Decode,\n    Upgrade,\n}\n\n// constructors","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/seanmonstar/reqwest/blob/9f06fd28abe53e5ff84a091825ea5ce8984b51e0/src/error.rs#L306-L342","documentation":"On wasm32 targets, reqwest implements From<crate::error::Error> for js_sys::Error (src/error.rs:321-326) by formatting the inner error with the Display trait into js_sys::Error::new(&format!(\"{err}\")). The literal source string is the placeholder \"{err}\"; the actual JS Error.message is the rendered text of whatever reqwest error (network, decode, status, builder, etc.) was raised. This is the boundary converter that lets a Rust reqwest::Error cross into JavaScript / wasm_bindgen as a throwable JS Error, not an error kind of its own.","triggerScenarios":"Any failed reqwest call in a wasm32-unknown-unknown build that is converted to a JsValue or js_sys::Error and propagated to JS: a fetch() that returned a non-2xx with .error_for_status(), a CORS rejection, an abort via AbortController, a URL parse failure, or a network failure in the browser. The conversion runs whenever ?-propagation reaches a function returning Result<_, wasm_bindgen::JsValue> or Result<_, js_sys::Error>.","commonSituations":"Browser-side reqwest builds (wasm) where the JS consumer catches the error and inspects .message. Confusion arises because the message is the reqwest Display string (e.g. \"error sending request\", \"HTTP status client error (404 Not Found) for url (...)\") rather than a stable error code. Version upgrades of reqwest that change Display wording silently change the JS-visible message. CORS misconfigurations are the most common real-world trigger.","solutions":["Inspect the JS Error.message in your catch handler against reqwest's Display strings, but prefer keeping error handling in Rust and only passing a structured/serialized payload (e.g. serde_json enum) across the boundary instead of relying on the opaque Display text.","Reproduce the underlying reqwest error in Rust by logging it before conversion (e.g. web_sys::console::error_1) to see the full Kind and source chain, which the JS message loses.","If you control the wasm binding, wrap reqwest results in your own enum and convert with serde_wasm_bindgen so JS sees typed error variants rather than a free-form message.","For CORS/status errors, fix the server's CORS headers or use .error_for_status() deliberately and map the Status kind yourself."],"exampleFix":"// before: opaque JS message\n#[wasm_bindgen]\npub async fn fetch_text(url: &str) -> Result<String, JsValue> {\n    let resp = reqwest::get(url).await?.text().await?;\n    Ok(resp)\n}\n\n// after: structured error crossing the boundary\n#[derive(serde::Serialize)]\npub enum FetchErr { Network, Status(u16), Body }\n\n#[wasm_bindgen]\npub async fn fetch_text(url: &str) -> Result<String, JsValue> {\n    let resp = reqwest::get(url).await.map_err(|_| FetchErr::Network.to_string())?;\n    let status = resp.status().as_u16();\n    let text = resp.text().await.map_err(|_| FetchErr::Body.to_string())?;\n    if status >= 400 { return Err(JsValue::from(FetchErr::Status(status).to_string())); }\n    Ok(text)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"// In JS consumer code\nfunction isReqwestError(e: unknown): e is Error {\n  return e instanceof Error && typeof (e as Error).message === \"string\";\n}","tryCatchPattern":"// JS side catching the wasm-thrown error\ntry {\n  const text = await fetch_text(url);\n} catch (e) {\n  // e.message is reqwest's Display string; surface to user or retry on network/CORS messages\n  if (/sending request|network|Failed to fetch/i.test((e as Error).message)) {\n    // transient, retry with backoff\n  } else {\n    throw e;\n  }\n}","preventionTips":["Do not rely on reqwest's exact Display strings as error codes; they can change between versions. Wrap into your own enum at the wasm boundary.","Log the full Rust-side error (Kind + source chain) via web_sys::console before converting to JsValue so debugging does not depend on the opaque message.","Handle CORS explicitly in dev (configure the dev server) to avoid the most common wasm fetch failure."],"tags":["wasm","wasm-bindgen","error-conversion","javascript-interop","browser"],"backgroundTag":null,"analyzedSha":"9f06fd28abe53e5ff84a091825ea5ce8984b51e0","analyzedAt":"2026-08-10T17:01:13.368Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}