jdx/mise · error
Got HTML instead of text from {}
Error message
Got HTML instead of text from {} What it means
After fetching text (usually JSON from an API) and applying retries, TextRequest::send checks whether the body starts with "<!DOCTYPE html>" (src/http.rs:1452-1463). APIs are expected to return text/JSON, so a leading DOCTYPE means an interstitial or block page came back. If the URL scheme was http, mise upgrades to https and retries once; otherwise it bails.
Source
Thrown at src/http.rs:1461
.client
.send_with_https_fallback_with_retries(
Method::GET,
url.clone(),
&headers,
"GET",
self.retries,
true,
)
.await?;
let text = resp.text().await?;
if text.starts_with("<!DOCTYPE html>") {
if url.scheme() == "http" {
// try with https since http may be blocked
url.set_scheme("https").unwrap();
self.url = Ok(url);
return Box::pin(self.send()).await;
}
bail!("Got HTML instead of text from {}", url);
}
Ok(text)
}
}
fn is_github_forbidden(url: &Url, resp: &Response) -> bool {
resp.status() == StatusCode::FORBIDDEN && url.host_str() == Some("api.github.com")
}
fn is_github_unauthorized(url: &Url, resp: &Response) -> bool {
resp.status() == StatusCode::UNAUTHORIZED && crate::github::is_github_api_url(url)
}
/// Maximum body bytes buffered when building a GitHub error report, so an
/// oversized or slow-trickling error response can't exhaust memory. The overall
/// request timeout bounds the time; this bounds the memory.
const MAX_ERROR_BODY_BYTES: usize = 64 * 1024;
View on GitHub (pinned to 6f52dcdf99)
Solutions
- Inspect what the URL returns in your environment: curl -sL <url> | head -c 300 — the HTML usually names the blocker (proxy, portal, rate limit).
- Use https:// URLs in configs; mise only auto-upgrades http once.
- Authenticate or allow-list the host on your proxy, or complete the captive-portal login.
- For GitHub API URLs, export GITHUB_TOKEN / MISE_GITHUB_TOKEN and check rate limits and githubstatus.com.
Example fix
# before $ mise use ubi:example/tool ERROR Got HTML instead of text from https://api.example.com/releases # after — clear the network condition, then retry $ curl -sL https://api.example.com/releases | head -c 100 # identify the blocker (portal/proxy) $ export HTTPS_PROXY=http://proxy.corp:3128 && mise use ubi:example/tool
Defensive patterns
Strategy: validation
Validate before calling
# CI preflight: endpoints must not return an HTML interstitial
curl -fsSL "$url" | head -c 15 | grep -q '<!DOCTYPE html>' && { echo "blocked/HTML response from $url"; exit 1; } Try / catch
On "Got HTML instead of text", stop and diagnose the environment (captive portal, proxy block page, rate limit) — retrying the same URL under the same network returns the same HTML. Re-attempt only after the condition changes: token set, portal cleared, proxy bypassed.
Prevention
- Use https and authenticated API endpoints in configs.
- Smoke-test critical URLs from the same network/CI environment before long runs.
- Set MISE_GITHUB_TOKEN for anything touching api.github.com.
- Check for captive portals on laptops before running mise.
When it happens
Trigger: A JSON/text endpoint returns HTML: captive portals on public Wi-Fi, SSL-inspection or DLP proxies substituting block pages, GitHub API rate-limit or interstitial pages, or a backend URL pointing at a website instead of the API — over plain http where even the https retry still returns HTML.
Common situations: Corporate laptops behind filtering proxies; hotel/airport Wi-Fi before login; a wrong URL (website path instead of API path) in a custom backend; heavy unauthenticated api.github.com use from shared CI IPs.
Related errors
- Got HTML instead of text from {url}
- cannot encode #{value.class} as JSON
- Failed to read schema at {}: {}
- Failed to parse schema JSON: {}
- cli feature is not enabled
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/fe2b4eaa343104d5.
Report an issue: GitHub.