{"record":{"id":"e0075b1f13db7d39","repo":"seanmonstar/reqwest","slug":"parsed-url-is-not-a-valid-uri","errorCode":null,"errorMessage":"Parsed Url is not a valid Uri","messagePattern":"Parsed Url is not a valid Uri","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/error.rs","lineNumber":392,"sourceCode":"        Kind::Status(\n            status,\n            #[cfg(not(all(\n                target_arch = \"wasm32\",\n                any(target_os = \"unknown\", target_os = \"none\")\n            )))]\n            reason,\n        ),\n        None::<Error>,\n    )\n    .with_url(url)\n}\n\npub(crate) fn url_bad_scheme(url: Url) -> Error {\n    Error::new(Kind::Builder, Some(BadScheme)).with_url(url)\n}\n\npub(crate) fn url_invalid_uri(url: Url) -> Error {\n    Error::new(Kind::Builder, Some(\"Parsed Url is not a valid Uri\")).with_url(url)\n}\n\nif_wasm! {\n    pub(crate) fn wasm(js_val: wasm_bindgen::JsValue) -> BoxError {\n        format!(\"{js_val:?}\").into()\n    }\n}\n\npub(crate) fn upgrade<E: Into<BoxError>>(e: E) -> Error {\n    Error::new(Kind::Upgrade, Some(e))\n}\n\n// io::Error helpers\n\n#[allow(unused)]\npub(crate) fn decode_io(e: io::Error) -> Error {\n    if e.get_ref().map(|r| r.is::<Error>()).unwrap_or(false) {\n        *e.into_inner()","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/seanmonstar/reqwest/blob/9f06fd28abe53e5ff84a091825ea5ce8984b51e0/src/error.rs#L374-L410","documentation":"Raised by url_invalid_uri() (src/error.rs:391-393) as a Kind::Builder error when a url::Url that parsed successfully cannot be re-parsed as an http::Uri. The conversion happens in try_uri() (src/into_url.rs:77-81) and is also checked at request execution time (src/async_impl/client.rs:2639-2642). The url crate is more lenient than the http::Uri parser, so a URL can be valid to url::Url but still contain characters or structures that http::Uri::from_str rejects, producing this error.","triggerScenarios":"Passing a URL whose host or path contains characters that http::Uri rejects even though url::Url accepted them: certain non-ASCII / Unicode bytes that were not percent-encoded, invalid percent-encodings, square-bracketed IPv6 literals with malformed scope IDs, or very long URIs exceeding http's internal limits. Also triggered by URLs with illegal whitespace or control characters that url::Url normalized but Uri cannot represent.","commonSituations":"User-supplied input containing Unicode (IDN hostnames, non-ASCII path segments) that wasn't percent-encoded before being passed to reqwest. URLs constructed by concatenating unescaped strings. Proxies or logs that mangle URLs with stray spaces. Rare edge cases in internationalized domain names where url's punycode handling and http::Uri disagree.","solutions":["Sanitize and percent-encode the URL with the url crate before sending: construct via Url::parse and call .as_str() to get the normalized, percent-encoded form that http::Uri accepts.","Percent-encode any user-supplied path or query segments with percent_encoding::utf8_percent_encode before building the URL string.","If the host is an internationalized domain name, convert to punycode (Url does this on parse) by always going through Url::parse rather than string concatenation.","Catch the error at the IntoUrl boundary and reject the input with a clear validation message rather than letting it surface at request time."],"exampleFix":"// before: raw concatenation may yield a Uri-rejected URL\nlet url = format!(\"https://example.com/search?q={}\", user_query);\nlet resp = reqwest::get(&url).await?;\n\n// after: go through url::Url so it is normalized + percent-encoded\nlet mut url = url::Url::parse(\"https://example.com/search\")?;\nurl.query_pairs_mut().append_pair(\"q\", &user_query);\nlet resp = reqwest::get(url.as_str()).await?;","handlingStrategy":"validation","validationCode":"fn validate_as_uri(raw: &str) -> Result<url::Url, String> {\n    let url = url::Url::parse(raw).map_err(|e| format!(\"URL parse: {e}\"))?;\n    // http::Uri is stricter; round-trip to catch the rejection early\n    raw.parse::<http::Uri>().map_err(|_| \"Parsed Url is not a valid Uri\".to_string())?;\n    Ok(url)\n}","typeGuard":"fn is_valid_uri(raw: &str) -> bool {\n    raw.parse::<http::Uri>().is_ok()\n}","tryCatchPattern":"match reqwest::get(url).await {\n    Ok(resp) => { /* ... */ }\n    Err(e) if e.is_builder() => {\n        // url_invalid_uri: re-encode the URL and retry, or reject the input\n        eprintln!(\"input URL rejected by http::Uri: {e}\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Construct URLs via url::Url and serialize with .as_str() so normalization + percent-encoding happens before http::Uri sees it.","Percent-encode all user-supplied path/query segments with the percent-encoding crate.","Reject non-ASCII hostnames at input and convert IDN to punycode through Url::parse."],"tags":["url","uri","parsing","percent-encoding","unicode"],"backgroundTag":null,"analyzedSha":"9f06fd28abe53e5ff84a091825ea5ce8984b51e0","analyzedAt":"2026-08-10T17:01:13.368Z","contentChangedAt":"2026-08-10T17:01:13.368Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}