jdx/mise · error

server returned inconsistent partial content

Error message

server returned inconsistent partial content

What it means

When resuming a download, mise cross-checks the server's 206 response against the recorded resume state: total length, ETag/Last-Modified validator, and returned byte range. Any inconsistency (plus a prior no-resume restart having occurred) means the remote file changed or the state is stale, so it clears the partial and bails.

Solutions

  1. Delete the partial download for that artifact and start the download fresh so state is rebuilt against the current file.
  2. Retry later if upstream is mid-release and the artifact is changing under you.
  3. Use a mirror that serves byte-identical artifacts with stable ETags/Last-Modified.

Example fix

// before
$ mise install node@22    # fails mid-resume: inconsistent partial content
// after: clear the stale partial and reinstall
$ rm -rf ~/.cache/mise/downloads/*node*22* && mise install node@22
Defensive patterns

Strategy: validation

Validate before calling

etag=$(curl -fsSI "$url" | grep -i '^etag:' | head -1)
[ "$etag" = "$stored_etag" ] || { rm -f "$partial"; echo "remote changed; clearing partial"; }

Prevention

When it happens

Trigger: A resumed download where Content-Range total differs from the recorded total, the response validator (ETag/Last-Modified) doesn't match the stored one, or the returned range doesn't line up with the resume offset — after a retry without resume already happened.

Common situations: Upstream replaced the artifact between the original partial download and the resume (version re-released); load balancer serving different file copies without stable ETags; stale partial from an old install attempt.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/de023c8acd737093. Report an issue: GitHub.

Appendix: source

Thrown at src/http.rs:1170

                        }
                        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 {
                            bail!("server returned inconsistent partial content");
                        }
                        restarted_without_resume = true;
                        continue;
                    }
                    // Keep the filename associated with the bytes already on disk.
                    // A redirect target may change between requests even when the
                    // server accepts the validator and Range header. Replacing the
                    // stored hint could make the completed bytes use a different
                    // archive format than the response that started the partial.
                    let effective_filename = state.effective_filename;
                    let validator = validator.unwrap_or(state.validator);
                    (
                        offset,
                        Some(total),
                        Some(validator),
                        true,
                        effective_filename,
                    )

View on GitHub (pinned to 533346cc37)