jdx/mise · error

server returned an invalid Content-Range response

Error message

server returned an invalid Content-Range response

What it means

During a resumed download, mise sent a Range request and the server answered 206 Partial Content, but the Content-Range header could not be parsed as a byte range (missing, malformed, or an 'unsatisfied'/'other' form). mise restarts the download once without resume; if the retry also fails to yield a parseable byte Content-Range, it gives up with this error. It protects against writing partial bytes at the wrong offset.

Source

Thrown at src/http.rs:1024

                if resp.status() == StatusCode::PARTIAL_CONTENT {
                    let Some((state, _)) = resume else {
                        partial.clear()?;
                        if !restarted_without_resume {
                            restarted_without_resume = true;
                            continue;
                        }
                        bail!("server returned partial content without a resumable request");
                    };
                    let content_range = resp
                        .headers()
                        .get(CONTENT_RANGE)
                        .and_then(|value| value.to_str().ok())
                        .and_then(parse_content_range);
                    let Some(ParsedContentRange::Bytes { start, end, total }) = content_range
                    else {
                        partial.clear()?;
                        if restarted_without_resume {
                            bail!("server returned an invalid Content-Range response");
                        }
                        restarted_without_resume = true;
                        continue;
                    };
                    let validator = response_validator(resp.headers());
                    let response_length_matches = resp
                        .content_length()
                        .is_none_or(|length| length == end - start + 1);
                    if start != offset
                        || end + 1 != total
                        || !response_length_matches
                        || state.total_size.is_some_and(|expected| expected != total)
                        || validator
                            .as_ref()
                            .is_some_and(|value| !value.matches(&state.validator))
                    {
                        partial.clear()?;
                        if restarted_without_resume {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Clear the partial download file/state (delete the .part file) and retry the download from scratch.
  2. Retry later or from a different network to bypass the misbehaving proxy/CDN.
  3. If you control the server/proxy, fix it to emit a valid 'Content-Range: bytes start-end/total' header on 206 responses.

Example fix

// before: download via corporate proxy that mangles Content-Range
export HTTPS_PROXY=http://proxy.corp:8080; mise install node@22
// after: bypass the proxy for tool downloads
export NO_PROXY=github.com,objects.githubusercontent.com; mise install node@22
Defensive patterns

Strategy: retry

Validate before calling

let range = headers.get("content-range").and_then(|v| v.to_str().ok());
let ok = matches!(range, Some(r) if r.starts_with("bytes ") && r.contains('/'));
if !ok { /* restart download from scratch, removing the .part file */ }

Try / catch

match download().await {
    Err(e) if e.to_string().contains("invalid Content-Range") => {
        remove_partial_download();
        download().await?; // fresh, non-resumed attempt
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling mise's HTTP download path (src/http.rs resume_download) against a server that responds 206 with a missing or unparseable Content-Range header, both on the initial resumed request and after the automatic restart-without-resume retry also returns a 206 whose Content-Range cannot be parsed.

Common situations: Downloading from a proxy, CDN, or misbehaving origin that emits 206 responses with non-standard or stripped Content-Range headers; middleboxes that mangle headers; caching proxies that return 206 from a stale entry.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/1bf11274e91962ba. Report an issue: GitHub.