{"record":{"id":"a2d073dbeca4a1d9","repo":"jdx/mise","slug":"got-non-html-text-from","errorCode":null,"errorMessage":"Got non-HTML text from {}","messagePattern":"Got non-HTML text from (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/http.rs","lineNumber":722,"sourceCode":"        }\n    }\n\n    pub(crate) async fn get_html<U: IntoUrl>(&self, url: U) -> Result<String> {\n        let url = url.into_url()?;\n        let resp = self.get_async(url.clone()).await?;\n        let is_html = resp\n            .headers()\n            .get(CONTENT_TYPE)\n            .and_then(|content_type| content_type.to_str().ok())\n            .is_some_and(|content_type| {\n                content_type\n                    .split_once(';')\n                    .map_or(content_type, |(media_type, _)| media_type)\n                    .trim()\n                    .eq_ignore_ascii_case(\"text/html\")\n            });\n        if !is_html {\n            bail!(\"Got non-HTML text from {}\", url);\n        }\n        let html = resp.text().await?;\n        Ok(html)\n    }\n\n    pub(crate) async fn json_headers<T, U: IntoUrl>(&self, url: U) -> Result<(T, HeaderMap)>\n    where\n        T: serde::de::DeserializeOwned,\n    {\n        let url = url.into_url()?;\n        let resp = self.get_async(url).await?;\n        let headers = resp.headers().clone();\n        let json = resp.json().await?;\n        Ok((json, headers))\n    }\n\n    pub(crate) async fn json_headers_with_headers<T, U: IntoUrl>(\n        &self,","sourceCodeStart":704,"sourceCodeEnd":740,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/http.rs#L704-L740","documentation":"get_html fetches a URL expecting an HTML page. After reading the response it checks the Content-Type (media type before any ';' charset suffix, trimmed, case-insensitive); if it is not text/html, it refuses to parse and throws this error.","triggerScenarios":"Calling HttpRedis/get_html on a URL whose server responds with a non-HTML Content-Type — e.g. application/json, text/plain, application/octet-stream, or a redirect target returning JSON.","commonSituations":"Scraping a plugin/tool index whose endpoint changed from an HTML page to a JSON API; a URL now redirecting to an API route or an error page served as text/plain; version-list scraping for a tool whose host changed its site.","solutions":["Point the caller at the actual HTML page URL (or the JSON API endpoint and parse JSON instead)","Check whether the host migrated its page layout/API and update the scraping logic in mise or the plugin","Disable any custom URL override (e.g. mirror/API env var) that redirects to a non-HTML endpoint","Update mise or the plugin so its list-URL matches the current upstream page"],"exampleFix":"// before\nlet html = http.get_html(\"https://example.com/api/versions.json\")?; // JSON endpoint\n// after\nlet html = http.get_html(\"https://example.com/downloads/\")?; // actual HTML page","handlingStrategy":"validation","validationCode":"let resp = reqwest::get(url).await?;\nlet ct = resp.headers().get(reqwest::header::CONTENT_TYPE)\n    .and_then(|v| v.to_str().ok()).unwrap_or(\"\");\nassert!(ct.starts_with(\"text/html\"), \"expected HTML, got {ct} for {url}\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Verify list URLs actually serve HTML pages, not JSON APIs","Track upstream site changes for tools you scrape","Prefer official JSON endpoints with json_headers when the host offers one"],"tags":["http","content-type","html"],"backgroundTag":"unexpected-response-shape","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}